STM32F746 Discovery tft "draw pixel" problems

Post here first, or if you can't find a relevant section!
Post Reply
jremington
Posts: 10
Joined: Thu Jun 18, 2020 2:19 pm

STM32F746 Discovery tft "draw pixel" problems

Post by jremington »

Hi, All:

I have run across a non-deterministic problem that may be due to an interaction between the display hardware access and program writes to RAM.

I'm using the LTDC lib associated with this branch of the core: https://github.com/fpistm/Arduino_Core_ ... TEST_1.9.0

UPDATED PROBLEM SUMMARY: in certain regions of the screen, the points commanded by drawPixel() do not appear in the same order with which they are commanded, sometimes with delays of seconds.

A simple program that demos the problem is posted below. It is intended to represent the path of a ball bouncing around the screen. Adding a delay, blocking or nonblocking, causes the draw routine to skip pixels. Pixels are skipped non-deterministically, and bizarrely, some are filled in after an arbitrary pause, as if memory writes are somehow queued and postponed. By non-deterministic, I mean that restarting the program results in a completely different pattern of skipped pixels.

Unfortunately the forum software does not allow me to post even a small, cropped (139 Kb) photo of the corrupted display ("file too large").

Suggestions appreciated!

Code: Select all

 // illustrates nondeterministic problem with the graphics library. 
 // Program restarts show different skipped pixels, if delay() is included in the code.
 
#include "LTDC_F746_Discovery.h"
// display has 480w X 272h pixels
#define H_RES 480
#define V_RES   272

LTDC_F746_Discovery tft;

int ballDirectionX = 1;
int ballDirectionY = 1;
int ballX = 10, ballY = 10, oldBallX = 10, oldBallY = 10;

// allocate screen buffer
uint16_t screen_buf[LTDC_F746_ROKOTECH.width * LTDC_F746_ROKOTECH.height];

void setup() {
  tft.begin(screen_buf);
  tft.fillScreen( LTDC_BLACK );
}

void loop() {
  moveBall();
//delay(1);  //*********************USE OF DELAY() CAUSES SKIPPED PIXELS
}

// this function determines the ball's position on screen
void moveBall() {
  // if the ball goes offscreen, reverse the direction:
  if (ballX > H_RES - 5 || ballX < 5) {
    ballDirectionX = -ballDirectionX;
  }
  if (ballY > V_RES - 5 || ballY < 5) {
    ballDirectionY = -ballDirectionY;
  }
  // update the ball's position
  ballX += ballDirectionX;
  ballY += ballDirectionY;
    tft.drawPixel(ballX, ballY, LTDC_WHITE);
}
Last edited by jremington on Mon Jul 26, 2021 4:29 pm, edited 5 times in total.
jremington
Posts: 10
Joined: Thu Jun 18, 2020 2:19 pm

Re: STM32F746 Discovery tft graphics library issue

Post by jremington »

Some progress was made by using delayMicroseconds() instead of delay(). Now, no pixels are skipped permanently, only transiently.

But the "draw" behavior clearly shows buffering of the graphics actions, as pixels initially skipped are filled in after an indeterminate pause. I don't understand how this could possibly work, as the draw action is to directly write to the screen memory buffer.

I would love for someone to explain this to me, but I suppose it has something to do with what the delay routine actually does. I'll look there next.

Here is the entirety of the LTDC drawPixel() routine:

Code: Select all

template <int W, int H>
void LTDCClass<W, H>::drawPixel(int16_t x, int16_t y, uint16_t color) {
    if (x >= 0 && x < W && y >= 0 && y < H) {
        buffer[x + y * W] = color;
    }
}
Current test code using delayMicroseconds():

Code: Select all

// use of delayMicroseconds() shows different drawing behavior

#include "LTDC_F746_Discovery.h"
// display has 480w X 272h pixels
#define H_RES 480
#define V_RES   272

LTDC_F746_Discovery tft;

int16_t ballDirectionX = 1;
int16_t ballDirectionY = 1;
int16_t ballX = 10, ballY = 10, oldBallX = 10, oldBallY = 10;

// screen buffer
uint16_t screen_buf[LTDC_F746_ROKOTECH.width * LTDC_F746_ROKOTECH.height];

void setup() {
  tft.begin(screen_buf);
  tft.fillScreen( LTDC_BLACK );
}

void loop() {

  moveBall();

delayMicroseconds(5000);
}

// this function determines the ball's position on screen
void moveBall() {
  
  // if the ball goes offscreen, reverse the direction:
  if (ballX > H_RES - 5 || ballX < 5) {
    ballDirectionX = -ballDirectionX;
  }

  if (ballY > V_RES - 5 || ballY < 5) {
    ballDirectionY = -ballDirectionY;
  }

  // update the ball's position
  ballX += ballDirectionX;
  ballY += ballDirectionY;

    tft.drawPixel(ballX, ballY, LTDC_WHITE);
}
jremington
Posts: 10
Joined: Thu Jun 18, 2020 2:19 pm

Re: STM32F746 Discovery tft graphics library issue

Post by jremington »

Well, the "draw hesitation" has nothing to do with the core function delayMicroseconds().

Here I replaced the call to delayMicroseconds() with a call to a function consisting of a "do nothing" loop written in assembly code. Same bizarre behavior, of pixels getting skipped, then filled in some time later.

I suppose the problem has something to do with how the display controller reads the shared memory and figures out which pixels to update. Assuming that to be the case, how can one introduce a delay that would not interfere with DMA reads? Time to read up on the display controller hardware!

Code: Select all

// in line assembly delay routine

#include "LTDC_F746_Discovery.h"
// display has 480w X 272h pixels
#define H_RES 480
#define V_RES   272

LTDC_F746_Discovery tft;

int16_t ballDirectionX = 1;
int16_t ballDirectionY = 1;
int16_t ballX = 10, ballY = 10, oldBallX = 10, oldBallY = 10;

// screen buffer
uint16_t screen_buf[LTDC_F746_ROKOTECH.width * LTDC_F746_ROKOTECH.height];

void setup() {
  tft.begin(screen_buf);
  tft.fillScreen( LTDC_BLACK );
}

static inline void delay_us(uint32_t us) {
    us *= 100;  //just a guess for the constant STM32_DELAY_US_MULT

    asm volatile("   mov r0, %[us]          \n\t"
                 "1: subs r0, #1            \n\t"
                 "   bhi 1b                 \n\t"
                 :
                 : [us] "r" (us)
                 : "r0");
}

void loop() {

  moveBall();

delay_us(50000);
}

// this function determines the ball's position on screen
void moveBall() {
  
  // if the ball goes offscreen, reverse the direction:
  if (ballX > H_RES - 5 || ballX < 5) {
    ballDirectionX = -ballDirectionX;
  }

  if (ballY > V_RES - 5 || ballY < 5) {
    ballDirectionY = -ballDirectionY;
  }

  // update the ball's position
  ballX += ballDirectionX;
  ballY += ballDirectionY;

    tft.drawPixel(ballX, ballY, LTDC_WHITE);
}
In case someone wonders, the same problem exists with this sort of "delay":

Code: Select all

if (micros() - lasttime > delayus) {
  moveBall();
  lasttime = micros();
 }
 
mrburnette
Posts: 633
Joined: Thu Dec 19, 2019 1:23 am
Answers: 7

Re: STM32F746 Discovery tft "draw pixel" problems

Post by mrburnette »

jremington wrote: Sun Jul 25, 2021 4:00 pm Assuming that to be the case, how can one introduce a delay that would not interfere with DMA reads? Time to read up on the display controller hardware!
I would think the better question is, "Why use delay() ?

I have not looked at Frederic's implementation of STM32duino's delay(), but generally speaking delay is a blocking function to the main loop() {code} BTW ... fpistm's github: This branch is 5 commits behind stm32duino:master.

Is that really what you want? Maybe look into an RTOS implementation (or scheduler or implement callbacks) to allow for better code synchronization... depending on the "Why..." answer.
jremington
Posts: 10
Joined: Thu Jun 18, 2020 2:19 pm

Re: STM32F746 Discovery tft "draw pixel" problems

Post by jremington »

Thanks for the response. As stated in the most recent post, use of the delay function is not the problem. A nonblocking approach using micros() shows exactly the same behavior as a blocking approach.

No method I've been able to come up with allows display of randomly placed dots on the screen, slowly and in the order commanded. The hardware or firmware rearranges the order in which the dots appear, sometimes with a lag of seconds!

To add a bit to the mystery, the problem is clearly related to how the display hardware accesses the memory. There exists a boundary about 1/3 of the way down the screen (about 1/3 of the way up in increasing screen buffer memory addresses) where it first appears.

Re:
This branch is 5 commits behind stm32duino:master
Does the master branch now support the STM32F476 Discovery touchscreen and display? It did not, when I started working with this board.
mrburnette
Posts: 633
Joined: Thu Dec 19, 2019 1:23 am
Answers: 7

Re: STM32F746 Discovery tft "draw pixel" problems

Post by mrburnette »

jremington wrote: Mon Jul 26, 2021 2:46 pm ...
No method I've been able to come up with allows display of randomly placed dots on the screen, slowly and in the order commanded. The hardware or firmware rearranges the order in which the dots appear, sometimes with a lag of seconds!

To add a bit to the mystery, the problem is clearly related to how the display hardware accesses the memory. There exists a boundary about 1/3 of the way down the screen (about 1/3 of the way up in increasing screen buffer memory addresses) where it first appears.

Re:
This branch is 5 commits behind stm32duino:master
Does the master branch now support the STM32F476 Discovery touchscreen and display? It did not, when I started working with this board.
I do not know the status of Frederic's merging of the F476 into the main branch ... my standard rule for responding in the forum is to avoid the off-branches unless you and Frederic have an agreement regarding testing/validation/etc.

Now, to track random pixels in the order they are set is not something that is normally done in uC hardware. To be able to track pixels in the order they are activated requires a kind of QoS (spatial dimension) as an attribute. Normally, stuff is just taken from the buffer by looping through the range; some authors gain efficiency by double-buffering with a shadow buffer (changed-bit per pixel per frame) to drive the bandwidth - not unlike digital TV. Of course, buffers can be built as FIFO, but "buffer-scanning" is the predominant method.

The economics afforded to TV methods are generally not applicable to uC with an attached display. A exception comes in technology such as FPV.

Considering the last statement, video libraries utilized for FPV may offer you some joy and may be worth the investigation.

Otherwise, I really do not see a happy ending to your existing concern with stock code other than to create/adapt your own graphics library.


Ray
jremington
Posts: 10
Joined: Thu Jun 18, 2020 2:19 pm

Re: STM32F746 Discovery tft "draw pixel" problems

Post by jremington »

I think the problem is in the HAL driver and/or display hardware. It works fine to display bitmaps and text, though.

I abandoned the STM32F746 Discovery for this project. The Teensy 3.2 processor and a 3.5" tft display does what I want.
User avatar
fpiSTM
Posts: 1738
Joined: Wed Dec 11, 2019 7:11 pm
Answers: 91
Location: Le Mans
Contact:

Re: STM32F746 Discovery tft "draw pixel" problems

Post by fpiSTM »

mrburnette wrote: Mon Jul 26, 2021 4:46 pm I do not know the status of Frederic's merging of the F476 into the main branch ... my standard rule for responding in the forum is to avoid the off-branches unless you and Frederic have an agreement regarding testing/validation/etc.
Well, this branch was created for test purpose and will probably never be merged in the main branch. It is provided "as it"
Post Reply

Return to “General discussion”