2019-11-20 07:49 AM
Hi @Martin KJELDSEN
On a screen I want to move two large images (one has transparency). I've implemented it like in your birdgame example (with the moveto(x,y) method.
Now I recognized that the animation is very slow and the rendering time is very long (>30ms). I don't know why this take so long. I measured it with the RENDER_TIME GPIO and also in SW. I see that the TouchGFX Library is active for more than 30ms.
Do you have any idea where the issue come from? Below you will find the implementation
Thank you
Best regards
Marco
#include <gui/containers/container_moving_waves.hpp>
#include <BitmapDatabase.hpp>
#include <touchgfx/Color.hpp>
container_moving_waves::container_moving_waves(): m_waveForeground(),
m_waveBackground(),
m_animationState(AnimationState::AnimationRunning),
m_tickCounter(0U),
m_tickinterval(1U) {}
void container_moving_waves::initialize()
{
container_moving_wavesBase::initialize();
initializeLayer(m_waveBackground, BITMAP_WAVE_BACKGROUND_ID, 255U, 1U, -1);
initializeLayer(m_waveForeground, BITMAP_WAVE_FOREGROUND_ID, 204U, 1U, 1);
m_boxWave.setPosition(0, 217, 800, 33);
m_boxWave.setColor(touchgfx::Color::getColorFrom24BitRGB(112, 148, 197));
add(m_boxWave);
}
void container_moving_waves::startAnimation() {
m_animationState = AnimationState::AnimationRunning;
}
void container_moving_waves::stopAnimation() {
m_animationState = AnimationState::NoAnimation;
}
void container_moving_waves::handleTickEvent() {
m_tickCounter++;
if ((m_tickCounter % m_tickinterval) != 0U) {
return;
}
if (m_animationState == AnimationState::AnimationRunning) {
moveLayer(m_waveForeground, m_tickCounter);
moveLayer(m_waveBackground, m_tickCounter);
}
}
void container_moving_waves::initializeLayer(Layer& layer, const BitmapId bmp, uint8_t alpha, const uint32_t animationUpdateSpeed, const int32_t animationWidth)
{
layer.image0.setBitmap(Bitmap(bmp));
layer.image1.setBitmap(Bitmap(bmp));
layer.image0.setXY(0, 0U);
if (animationWidth < 0) {
layer.image1.setXY(layer.image0.getRect().right(), 0U);
}
else {
layer.image1.setXY(layer.image0.getRect().x - layer.image1.getWidth(), 0U);
}
layer.image0.setAlpha(alpha);
layer.image1.setAlpha(alpha);
add(layer.image0);
add(layer.image1);
layer.animationUpdateSpeed = animationUpdateSpeed;
layer.animationWidth = animationWidth;
}
void container_moving_waves::moveLayer(Layer& layer, const uint32_t tickCount) {
if ((tickCount % layer.animationUpdateSpeed) == 0U) {
layer.image0.moveTo(layer.image0.getX() + layer.animationWidth, layer.image0.getY());
layer.image1.moveTo(layer.image1.getX() + layer.animationWidth, layer.image1.getY());
if (layer.animationWidth < 0) {
//when moving left
if (layer.image0.getRect().right() < 0) {
layer.image0.moveTo(layer.image1.getRect().right(), layer.image0.getY());
}
if (layer.image1.getRect().right() < 0) {
layer.image1.moveTo(layer.image0.getRect().right(), layer.image1.getY());
}
}
else {
//when moving right
if (layer.image0.getRect().x > layer.image0.getWidth()) {
layer.image0.moveTo(layer.image1.getRect().x - layer.image0.getWidth(), layer.image0.getY());
}
if (layer.image1.getRect().x > layer.image1.getWidth()) {
layer.image1.moveTo(layer.image0.getRect().x - layer.image1.getWidth(), layer.image1.getY());
}
}
}
}
2019-11-20 11:49 AM
Hi Marco,
I'd have to know more about your hardware setup. i think. How did you create this project? Is ChromART enabled? If so moving data from flash to framebuffer should only impact your render time minimally. What is the render time for a static frame?
Can you double check settings?
/Martin
2019-11-21 12:49 AM
Hi @Martin KJELDSEN
Thank you for your reply. Here are some more information
Hardware-Setup:
We are using embOS and created the project initially with TouchGFX 4.9.3.
The rendering time for a static frame with 4 buttons without images is about 15ms. With the moving images like above the rendering time is >70ms. The 30ms from the first post where with some optimization (only one wave,...)
I've made a more detailed analysis (see attached excel file). There are 5 "delays" with more than 7ms where the TouchGFX Library is doing something but I don't know what. Do you have any idea what happens there?
I would highly approciate, if you could invest some time for investigation. I can provide you more information if necessary, but I can't share the project within the forum.
Thank you very much
/Marco
Renderingtime static screen:
Renderingtime moving images:
2019-11-21 12:58 AM
Is your QSPI set up properly? Reading from QSPI will also impact render time, regardless of ChromART.
2019-11-21 02:20 AM
Yes, QSPI is set up in memorymode and runs at 108MHz. (measured on hardware)
What I'm wondering is whether the 15ms for a static frame is also much too long, although there is no need to access the QSPI Flash.
What I noticed is that setupDataCopy is never called. Shouldn't this method be called if a data should be transfered from Flash?
2019-11-21 04:49 AM
Yes, as i suspected you're not using the ChromART chip to transfer data to the framebuffer from QSPI. That's why i asked "Is ChromART enabled?" - But now i'm realizing i was too vague in my request.
Show me your touchgfx configuration (Maybe in boardconfiguration.cpp) and we'll be able to tell in no time probably.
/Martin
2019-11-21 05:54 AM
I'm enabling ChromART through enabling the following bits:
ACR->ARTEN
AHB1EN->DMA2DEN
Do I have to do something else?
Additionally I will send the configuration file directly to you.
Thanks
/Marco
2019-11-21 06:31 AM
This is not enough - TouchGFX needs to know that it should use DMA2D to start data transfers. We have a dedicated class that knows how to use DMA2D to transfer "TouchGFX BlitOps" - Init of TouchGFX must include this.
Could you show me your touchgfx_generic_init() function? I'm not sure where it's located in your project.
/Martin
2019-11-21 06:38 AM
STM32F7DMA dma;
STM32F7TouchController tc;
STM32F7Instrumentation mcuInstr;
static LCD24bpp display;
static uint16_t bitdepth = 24;
namespace touchgfx
{
void touchgfx_init()
{
uint16_t dispWidth = 480;
uint16_t dispHeight = 272;
HAL& hal = touchgfx_generic_init<STM32F7HAL>(dma, display, tc, dispWidth, dispHeight,(uint16_t*) 0,
0, 0);
The above code is an example of the init of TouchGFX using an STM32 DMA class. Then, to give you an idea, somewhere in that class we'll start a transfer using the parameters of the BlitOp given to use from one of the LCD classes:
HAL_DMA2D_BlendingStart_IT(&hdma2d,
(unsigned int)blitOp.pSrc,
(unsigned int)blitOp.pDst,
(unsigned int)blitOp.pDst,
blitOp.nSteps, blitOp.nLoops);
/Martin
2019-11-21 07:11 AM
Thats the code for the touchgfx initialization
static LCD16bpp display; //lint !e956 Justification: required by TouchGFX
static TouchGFX_P3_DMA dma; //lint !e956 Justification: required by TouchGFX
static TouchGFX_P3_TouchController tc; //lint !e956 Justification: required by TouchGFX
void SystemInitializationDriver::initTouchGFX() {
HAL& hal = touchgfx_generic_init<TouchGFX_P3_HAL>(dma, display, tc, 800U, 480U, 0U, 0U, 0U);
// setup for double buffering
void* pMemBaseAddressSdram = reinterpret_cast<void*>(MEM_BASEADDRESS_SDRAM); //lint !e923
hal.setFrameBufferStartAddress(pMemBaseAddressSdram);
// The optimized strategy for single buffering requires the presence of a task delay function.
// hal.registerTaskDelayFunction(&OSWrappers::taskDelay);
// setup touch parameter
hal.setTouchSampleRate(1);
hal.setFingerSize(1U);
// by default frame rate compensation is off.
// Enable frame rate compensation to smooth out animations in case ther is periodic slow frame rates.
hal.setFrameRateCompensation(false);
// this platform can handle simultaneous DMA and TFT accesses to SDRAM, so disable lock to increase performance
hal.lockDMAToFrontPorch(false);
// MCU Instrumentation -> Todo: at the moment this feature is not used. the following lines is an example for initalization.
// This can be deleted in productive version
// Set MCU instrumentation and Load calculation
//mcuInstr.init();
//hal.setMCUInstrumentation(&mcuInstr);
//hal.enableMCULoadCalculation(true);
}
I understand, that the DMA2D method should be called. My problem is that the method setupDataCopy within the DMA class will not be called by the touchgfx library. The other method setupDataFill (which is in the same class) will be called correctly.
Meanwhile I did a performancetest for QSPI. I get a troughput of about 50MBps. So this should not be the problem.
Is there anything else I should verify?
Thanks
/Marco