Screen tearing on LCD displays - Page 1
Forum section: electronics / general

author: SiliconWizard
author_rank: Super Contributor
timestamp: September 12, 2024, 10:08:09 pm
content: It's not really specifically a microcontroller problem, but still looks like the most appropriate section.I'm currently on a project which uses a TFT display (namely a 320x170 TFT with a ST7789V2 controller, pretty nice display btw) and am running into screen tearing issues. Although I control it via SPI, I can get pretty high update rates (SPI @50 MHz) and when updating some parts fast enough, I get screen tearing. Which isn't pretty.I have used quite a few LCD displays before but never with very fast updates so I've never really bothered with this screen tearing thing.Of course it's all a matter of synchronizing GRAM updates with the vertical sync, but I don't know how this can be done with those LCD controllers. I've seen that some controllers have a sync signal output that can be used to handle GRAM writes at the right times. But I don't have access to such a signal here. So is this a lost cause? I've seen in the controller DS that there are some related commands, such as "Set Tear Scanline", but I don't really understand how that's supposed to work.Ideally, you'd do some double-buffering, but I don't think it's possible with such a controller that only has enough GRAM for one frame. (Actually this controller has enough for 320x240 so there should be a spare 320x70 block in my case, but I don't know if than can be useful.)If anyone has dealt with this kind of issue before...

author: globoy
author_rank: Frequent Contributor
timestamp: September 12, 2024, 10:35:07 pm
content: Yes, this is a pain with this kind of display.Quote from: SiliconWizard on September 12, 2024, 10:08:09 pmI think that some controllers (maybe the ILI stuff) had the ability to set the starting point in GRAM in order to implement a smooth scroll feature. I wonder if the ST part has that and if you could use that to implement a double buffer. Set the starting line so one part of GRAM shows while writing the other, then swap.

author: SiliconWizard
author_rank: Super Contributor
timestamp: September 12, 2024, 11:03:17 pm
content: Quote from: globoy on September 12, 2024, 10:35:07 pmYes it does implement scrolling - actually the commands are pretty "standard" across TFT controllers, it seems.So that may be something to try. As I said, it doesn't have enough GRAM for two full display buffers. But if I only update partial areas, the extra GRAM available in my case may be enough. (Since it's tied to the screen format you set, the spare 320x70 in my case is just that, 320x70, so that I could not use more than 70 lines for double buffering. Better than nothing.)

author: thm_w
author_rank: Super Contributor
timestamp: September 12, 2024, 11:11:08 pm
content: The signal is "TE" tearing effect. Is there any way you can get a new display with that extra signal? Some have it, some don't.https://hackaday.io/project/192130-felini-revolutionary-pocket-sized-electronic-lab/log/223577-tearing-effect-st7789https://github.com/AGlass0fMilk/mbed-lvgl/issues/4https://forums.adafruit.com/viewtopic.php?t=208023

author: SiliconWizard
author_rank: Super Contributor
timestamp: September 12, 2024, 11:20:13 pm
content: Quote from: thm_w on September 12, 2024, 11:11:08 pmI will look into that.Although it would obviously be hit-or-miss, I can try tweaking the refresh rate setting. Otherwise using scrolling could work but as I said, the extra GRAM is limited.

author: radiolistener
author_rank: Super Contributor
timestamp: September 12, 2024, 11:31:36 pm
content: Quote from: SiliconWizard on September 12, 2024, 10:08:09 pmUsually this is solved by waitng vblank synchronization event from display controller. Probably this "Set Tear Scanline" is the replacement for this, at a glance it looks that you can setup which scanline will be used for waiting vblank event, so when you send this scanline it will wait for vblank pulse and doing buffers swap to avoid screen tearing. So try to use this command and see what happens...For testing screen tearing issue you can fill every new frame with different color, for example black and white. It should blink with no tearing artifacts.With no proper vblank synchronization you will not be able to remove screen tearing artifacts. Even if you use double buffering, buffer swap should be synchronized with vblank event, otherwise it will give you tearing artifacts.

author: globoy
author_rank: Frequent Contributor
timestamp: September 13, 2024, 01:36:23 am
content: Quote from: SiliconWizard on September 12, 2024, 11:03:17 pmSorry about that. You did mention it. For some reason I thought you were using a 320x70 resolution TFT!

author: SiliconWizard
author_rank: Super Contributor
timestamp: September 13, 2024, 01:49:14 am
content: Using scrolling would be the only way to get a synchronized update though. So I may try that - it will be limited, but for some animations that could work. (And screen tearing is most visible when animating stuff.)Otherwise, the only way is to get the TE signal and that requires a display that exposes it.

author: radiolistener
author_rank: Super Contributor
timestamp: September 13, 2024, 03:39:30 am
content: Without proper vlbank sync you won't be able to update screen with no screen tearing artifacts. You can only hide it for some cases. But it can appear and disappears at random event.Is your display have TE output? Did you tried to send "Set Tear Scanline" command?If it don't have TE, you can try to implement spinlock with executing "Get Scanline" command and start to update frame when scanline reach some value (can be chosen with testing).It's the same as testing TE signal, but less stable because needs some delay for "Get Scanline" command execution.If "Get Scanline" execution has too long delay, you can synchronize current scanline with "Get Scanline" command with your CPU high resolution timer and interpolate it's result between "Get Scanline" reading. But it requires continuous synchronization between "Get Scanline" and your local timer, because their clocks are asynchronous.

author: SiliconWizard
author_rank: Super Contributor
timestamp: September 13, 2024, 05:36:28 am
content: - As we discussed above already, no, my display does not expose the TE output, and yes, that would be the better option here. But I've looked, and off-the-shelf panels that expose TE seem relatively rare.- All the "tearing" commands only configure the TE output, they don't do anything else, so would be of no use if I can't use TE.- The "Get Scaline" command could be an option indeed. Didn't think of that. But it would be pretty inefficient, especially since I use SPI (I didn't even implement reads, but while many TFT controllers don't support reading in SPI mode, this one does, so that can be something to experiment). Yes I understand the idea you give to get the current scanline at some point, associate it with an internal timestamp and thus "interpolate" the probable current scanline without having to re-read it. That would have to be resynchronized on a regular basis though since the respective clocks are completely unsynchronized themselves. Not ideal, but an idea that can be explored.Note that even with the TE output, these controllers with integrated GRAM (and no provision for double buffering) have limited abilities for synchronized updates - to avoid any tearing, you'd have to write *only* during vertical blanking, which can be pretty short. With a bit more elaborate algorithm, you can of course, again, interpolate the probably current scanline from the TE signal, and update parts of the GRAM that have been already scanned. Kinda awkward.For sure the best option is to be able to control the panel in RGB mode (so handling the framebuffer and sync ourselves), but that requires a FPGA or a CPU that can support that, which isn't the case here. But that allows maximum efficiency and the use of double, or even triple buffering, if one has enough RAM available.I have otherwise experimented a much simpler approach of tweaking the refresh rate parameter, and that does help, making visual artefacts almost invisible to the naked eye (but probably still very visible when taking pictures with fast speed). Sure this approach is more like a trick than anything else and requires adapting the refresh rate to the types of updates you're doing, but that seems workable. Not very pretty, but somewhat usable. Of course one has to determine if a varying refresh rate is acceptable or not.As to the scrolling trick, it works, but relies here on the fact that I have some spare GRAM available, and only works to update the 70 bottom (or possible top, if I can configure the scan addresses properly) lines, as it consists in writing in the GRAM part outside of the visible area and then scroll it in from the bottom, which can only be contiguous, so only from the bottom line and not from a random line in the viewport. The scrolling is synchronized to Vsync, so that does the trick, with the said limitations.

author: Smokey
author_rank: Super Contributor
timestamp: September 13, 2024, 08:57:47 pm
content: I did a project with an SPI interface 320x240 display a while ago. I also had tearing problems but there wasn't much I could do about it with the SPI interface (even running it at 80MHz). There were just more pixels to push than there was time before screen refreshes.Numbers:320x170 = 76800 pixels.Assuming best case of RGB565, that's 16bits per pixel (it gets worse if you are using 18bit or 24bit per pixel).So 1,228,800 bits per full screen write.At 50MHz SPI, that's 24.5ms per full screen data transfer.Unless your display refresh period is slower than about 25ms (40Hz), you can't do a full screen write without spanning two refreshes and see a tearing line.Sorry if this is obvious and not part of your problem.

author: SiliconWizard
author_rank: Super Contributor
timestamp: September 13, 2024, 11:02:36 pm
content: Well, yes, obviously communication speed limits the rate at which you can update frames, but it is actually not *directly* related to screen tearing.Screen tearing will occur when you update parts of GRAM that are currently being scanned. This can happen whatever the speed at which you can write to GRAM is. It's a matter of synchronization.As I mentioned, short of being able to do real double-buffering, your closest bet would be to wait for Vsync (which you can get from TE, which I don't have access to), then either write only during Vsync, or start writing at the beginning of Vsync and then continue writing while making sure that you don't overwrite parts of GRAM that's currently being scanned, which would allow you to update one full frame - that would be a poor man's double buffering, but relatively "tricky" to implement.Now even with that scheme, of course, if writing a full frame takes longer than a frame period, you just can't. But then you'd just split your updates over several frames on areas that are unrelated. That adds constraints for how you lay out your display elements.In practice: unless you do repeated full frame updates (like for playing videos full screen), you don't necessarily update the whole area at once. In my typical use cases, I rarely have to update more than about 50% of the whole area, at least repeatedly. That's the repeating patterns ("animations") that make the tearing really obvious. If you just update areas that then remain still for a bit, screen tearing is almost non noticeable.One type of "animation" I use that made it very noticeable are "vumeters" updated in "real-time". More "static" updates are not really a problem.As I mentioned, playing with the refresh rate on the fly (which actually works, I was not sure, feared it could cause refreshes to stop while updating it, but nope!), while a bit of a hack, works surprinsingly well in my case. They don't document when the change is exactly taken into account (I'm guessing on the next frame period following the command), but it creates no artefact when changing and there's a relatively large span of 39 Hz to 119 Hz with relatively fine steps. Hacky, but interesting.

author: thm_w
author_rank: Super Contributor
timestamp: September 13, 2024, 11:17:56 pm
content: Just for reference for hobbyist use, as I'm sure you won't be sourcing from aliexpress, but TE broken out displays are not hard to find there:https://www.aliexpress.us/item/3256805743944668.html

author: Postal2
author_rank: Frequent Contributor
timestamp: September 14, 2024, 01:14:16 am
content: Quote from: SiliconWizard on September 13, 2024, 11:02:36 pmThe datasheet also describes a method to prevent tearing: (picture).I'll tell you how to use it. Set framerate to 40, perform off-on according to the picture, and start filling the memory at a minimum speed of 20. Scanning will catch up with you at the end of the second pass.If you connect reading and your speed is 30, then you can check for Get Scanline to hit the upper half of the frame and start filling after that.

author: Nominal Animal
author_rank: Super Contributor
timestamp: September 15, 2024, 05:23:38 am
content: Quote from: SiliconWizard on September 12, 2024, 10:08:09 pmI pickBuyDisplay/EastRising IPS panelsthat do export the TE pin, for exactly this reason. Of the 320×170 and 320×172 IPS ones, none do, currently. Are you usingER019-1? The controller does have the pin, it's just not exported on the 30-pin, 0.35mm pitch FPC, which is silly because pin 24 between GND and a NC (not connected) pin is not connected; they could have used that one.1.09" 240×240 IPS (GC9A01, round, 2V+2.8V),1.32" 360×360 IPS (GC9C01, round, QSPI only),2" 240×296 IPS (GC9307N, rounded corners),2.4" 320×240 IPS (ST7789VW),2.8" 320×240 IPS (ILI9341),3.2" 320×240 IPS (ST7789V2, FMARK=TE), and3.5" 480×320 IPS (ILI9488)do, for example.Don't let the unfamiliar controller names scare you, either: they're all very similar, and in any case, the controller datasheet including commands/registers and details are included on every product page. All these support either SPI or QSPI (but may reserve the entire bus, I haven't checked); some also support one or more parallel data modes (because the mode selection pins are also exported). Some of the controllers do not support high SPI clock rates, officially, so do check the provided specs before choosing one –– especially if you're designing a product rather than an one-off. (ILI9xxx are known to support rather high SPI clock rates in practice: 80 MHz was reported in one particular case, IIRC, even though the datasheet says something like 15 MHz or so is the official maximum.) Also, backlight LED voltage and current requirements vary, so be prepared to do your own. That's an adventure...The 2.8" one is my current favourite. If I could do BGA (my own Teensy 4 compatible exposing the eLCD pins), I'd use the SPI+RGB IPS panels.

author: Siwastaja
author_rank: Super Contributor
timestamp: September 15, 2024, 05:34:30 am
content: The idea of periodically reading out "current scanline" and keeping track of its change rate to create a synchronized internal approximation of it, then use this value to time the writes to the display sounds like an idea which could really work reliably, and it's notthatmuch work..?

author: Smokey
author_rank: Super Contributor
timestamp: September 15, 2024, 05:49:21 am
content: I had the BuyDisplay guys make me a custom shaped touch glass to go on one of their stock displays. It was surprisingly reasonably inexpensive. Recommend.

author: Nominal Animal
author_rank: Super Contributor
timestamp: September 15, 2024, 06:02:53 am
content: Quote from: Siwastaja on September 15, 2024, 05:34:30 amAlmost all controllers do expose such a command, indeed.GC9A01A:Get Scanline (0x45)(PDF p. 142).GC9C01:Get Scanline (0x45)(PDF p. 218).GC9307:Get Scanline (0x45)(PDF p. 141).ST7789:Get Scanline (0x45)(PDF p. 231).ST7789V2:Get Scanline (0x45)(PDF p. 233).ILI9341:Get Scanline (0x45)(PDF p. 140).ILI9488:Read Scan Line (0x45)(PDF p. 205).I wasn't kidding when I said they're all very similar to each other. It is common for only the setup commands to vary.With SPI and an MCU with a high-resolution timer interrupt available, I would suggest using a timer interrupt designed to track the scan line following the last visible one, adjusting the period (gently!) to stay in sync, with the interrupt checking the scan line, adjusting the period if necessary, and sending the command part of the update, and triggering the bulk data send via DMA if the frame is ready. Some display modules only support 4-wire SPI, where the extra line is for data/command bit, and this scheme fits those perfectly because then the DMA'd data is pure data (no D/C bits in it).Note "gently!": it doesn't matter if the interrupt is slightly late, as long as it isn't too much late, and never too early. So adjustments should be gradual, based on the lastNframes, rather than only the previous interval. Compare to e.g. NTP time adjustment schemes, they're very similar.The downside is the interrupt duration: the D/C pin is deasserted after the command part, between the command and data. So, you can't just use the SPI FIFO if you have one. If you don't mind the added complexity, you can use DMA for both, just separately: the timer interrupt triggering the command DMA with D/C asserted. The DMA completion interrupt deasserts D/C, and triggers the data DMA.I personally use the parallel data instead, because I do want full screen updates without tearing, and for most displays SPI just don't cut it.

author: peter-h
author_rank: Super Contributor
timestamp: September 18, 2025, 08:00:03 pm
content: Just found this thread. I posted herehttps://www.eevblog.com/forum/microcontrollers/fonts-and-driving-lcd-controllers-for-drawing-text/msg6042563/#msg6042563ISTM that using TE to avoid tearing implies a frame buffer, which most embedded systems do not have.If you are drawing "random graphics" then the best you can do is restrict the command sending to the TE=1 period, which is unlikely to be much over 1ms (2ms can be done with say a 30fps frame rate) and it will run very slowly - unless you are updating just a small part of the screen e.g. a line of text.

author: Nominal Animal
author_rank: Super Contributor
timestamp: September 18, 2025, 09:59:43 pm
content: Quote from: peter-h on September 18, 2025, 08:00:03 pmYes. Or only updating a very small region.I've done some funky (mostly thought-) experiments around this issue, including using two or three separate PSRAM chips in ping-pong fashion, and small simple slave MCU controlling and updating the display from the PSRAM not currently being written to by the main microcontroller. It is a surprisingly affordable solution, in my opinion. The nicest thing about it is that if you pair the small slave microcontroller with the display, all the display module specific code is restricted to the slave, so your main microcontroller does not need to deal with that stuff at all. To replace the display, you also replace the slave microcontroller. Depending on the PSRAM size, you usually also have memory enough for multiple planes, so that often-varying things are on a LUT-based overlay plane, say 8 bits per pixel, and instead of copying back data from a previous frame you simply clear the overlay plane to zeros. The slave MCU then combines these into the full frame data sent to the actual display.

author: SiliconWizard
author_rank: Super Contributor
timestamp: September 18, 2025, 11:49:08 pm
content: Interesting option - that's something that would be a good fit for the RP2350, which is very cheap, supports QSPI PSRAM, would support pretty much any LCD interface with its PIO, and with its dual-core M33 , should be enough in terms of processing - all the more that it also has two "interpolators" which should accelerate blending operations.

author: Nominal Animal
author_rank: Super Contributor
timestamp: September 19, 2025, 03:06:13 am
content: An RP2350 by itself would suffice as a slave UI processor, because it has ample memory for a framebuffer (up to 480×480 or 640×360 at RGB565/16-bit color), and PIO can easily drive small display modules in 8-bit/9-bit/16-bit/18-bit parallel mode. One could use e.g. UART at a high baud rate as a full duplex asynchronous pipe between the master and the slave RP2350, describing changes in values (so the exact UI design would be limited to the RP2350 only). This works well for menu-type UIs, clocks, gauges and similar.Considering that one can buy them in singles off Mouser for 0.69€/$0.80, it is certainly one possible solution. If one carefully follows the hardware design notes, that is.As an USB-connected display controller, RP2040 and RP235x are severely limited by their low/full speed USB interface, maximum 12 Mbit/s or about 1 Mbyte/second in one direction; much less with bidirectional data flow. I may have been spoiled by USB 2.0 high-speed devices, though..

author: peter-h
author_rank: Super Contributor
timestamp: September 19, 2025, 06:09:16 am
content: I do have an 8MB PSRAM - LY68L6400SLhttps://www.eevblog.com/forum/microcontrollers/lyontek-ly68l6400-8-megabyte-spi-sram-am-i-reading-the-data-sheet-right/msg4193821/#msg4193821I spent a bit of my life determining the /CE=1 limits for this weird chip! It couldnotbe used for a frame buffer if you want to DMA the whole 320x480x3 block in one go. I was hoping that reading a huge chunk would perform a refresh (like it did with the old DRAMs) but it apparently does not.QuoteIndeed. But how to do that in the context of FreeRTOS, when the TE=1 pulse is only 1ms? I believe there is a way to use an interrupt to release a suspended task. Funnily enough I have never done this, although there appear to be several ways. I think you use vTaskSuspend() to suspect the graphics task just before you want to write the data, and have an ISR (triggered by TE=1 edge) execute xTaskResumeFromISR().For anything bigger than trivial you end up with an update spread across multiple frames. For example the clock examplehttps://www.eevblog.com/forum/microcontrollers/fonts-and-driving-lcd-controllers-for-drawing-text/msg5961597/#msg5961597takes about 30ms (that's graphics via SPI, not any calculations which are very fast) so it would be spread across 30 frames i.e. 0.5 of a second. I have tried this (using a hack with a tight loop waiting for TE=1) and it doesn't work at all visually.And even using a frame buffer, 320x480x3 bytes, takes 175ms at 21MHz SPI to transfer, so no chance of doing the "classic" approach of waiting for TE=1 and then moving the frame buffer to the display at a speed slightly slower than the display controller reading it out. At 60fps, you need to get this down to 17ms i.e. ~200 megabits/sec. That is driving a 24 bit parallel bus at 9MHz.So this simply does not add up. As you say, OK for drawing little bits only, OR a frame buffer and a parallel transfer using DMA.

author: SiliconWizard
author_rank: Super Contributor
timestamp: September 19, 2025, 01:58:23 pm
content: Quote from: Nominal Animal on September 19, 2025, 03:06:13 amYes, I was more considering using it as a slave controller with SPI or even a parallel bus implemented with the PIO, or whatever else fits. Also, if it's a slave controller part of your device, it can implement the full UI instead of just being a "display controller" and thus the required bandwidth can be rather limited.We can wish for USB HS on the next RPi iteration of MCUs, and maybe that will be the case. I don't know. USB HS IPs are relatively expensive.

author: nctnico
author_rank: Super Contributor
timestamp: September 19, 2025, 02:51:44 pm
content: Quote from: SiliconWizard on September 12, 2024, 10:08:09 pmIf the display has a way to do block copies, you could create a screen update in the 320x70 block and let the display controller copy that. A crude double buffering scheme.But how is the display information updated? Is the data written in the same direction as the vertical trace direction? An interesting experiment is to write the display memory from bottom to top. So against the direction of the vertical trace direction. This minimises the overlap of the display reading pixels from the memory and you updating the memory. I have never tried this myself but I think it could be worth a try.

author: Nominal Animal
author_rank: Super Contributor
timestamp: September 19, 2025, 03:22:58 pm
content: Quote from: SiliconWizard on September 19, 2025, 01:58:23 pmExactly.I do like UART for this, at as high baud rate as you can use without errors, because it is full duplex, perfectly matching my UI-to-master communications model.The idea there is that the UI provides the state-changing events, but does not e.g. update the display with the new value until the master responds. I also like to allow more than one event in flight at any time. A full duplex, asynchronous interface (as opposed to e.g. SPI) makes this easy to implement.In practice, this means that when the user pushes a button or turns a knob to change some value, the UI calculates the new value, and sends it to the master, but does not update the display yet. Only when the master returns the new set value — and it may even clamp it or round it to the nearest supportable value —, does the UI update the displayed value. Similarly, the master can push updates to state values whenever they change, be they user-modifiable or just indicators (for gauges and such).This makes the UI very responsive, in the sense that what youseeis what the masteruses; the two are never out of sync. This is extremely important in my opinion. It is horrible when you cannot tell if the value you see is actuallyappliedor not: it makes you distrust the device altogether.I apply the same with application UIs, especially when the UI part is written in some high-level language like Python to make it easier for even end-users to modify, and the application core is native machine code (a dynamically loaded library).Here, too, the communications protocol used between the master and the RP2350 slave makes a big difference. You do want to implement all of the UI in the RP2350, and only pass the state value modification requests and responses between the two. I much prefer a binary protocol here, but the details really depend on whatkindof state you pass between the two. Do not make it require a response before a new request is made; do treat each side of the connection as its own one-directional pipe of information, with the two pipes basically unrelated. One trick I like to do is have each message always start with a nonzero byte, so one can use a sequence of zeros to "flush" any crud after a parity error, and resync. I also warmly suggest using a single-byte resync request, itself followed by a number of zeros, the depth depending on the UART peripheral FIFO sizes on the two MCUs, automatically used whenever a parity error is observed. It should be exceedingly rare, yes, but making that automatically (and having a way to test it) makes the device much nicer when those rare events — maybe a welding arc nearby — do occur, as instead of starting to produce garbage or plain jamming up, it just hiccups and then continues working without errors.While using two different MCUs with different architectures may sound like added development effort, I've found that it actuallysimplifiesthe implementations. For example, if you use something like LVGL, here you only need it on the UI MCU, not on the master MCU at all. If the comms protocol is well designed, the complexity of the two microcontrollers is a fraction of what combining their tasks on a single MCU would be. That said, I'm extremely comfortable doing parallel and distributed stuff, so maybe the way I think is wonky and just fits that.. but we do have decades of success applying theUnix philosophy, so I do have reason to believe it is also more generally true.Quote from: SiliconWizard on September 19, 2025, 01:58:23 pmThey (the Foundation and Broadcom) don't have exactly a stellar record with USB implementations, either. PIO is extremely interesting and nice for these projects, but I do consider the USB side the fatal weakness for RP2040 and RP2350. But, for cases where one does not use the USB for anything other than firmware uploads or other rare updates, it definitely is an MCU one should consider using.

author: peter-h
author_rank: Super Contributor
timestamp: September 19, 2025, 08:42:15 pm
content: I have the interrupt from TE and the video sync working. Took me all day. I got a bit of help on the ST forum and posted my code therehttps://community.st.com/t5/stm32-mcus-embedded-software/32f417-trying-to-interrupt-from-pe12-rising-edge/m-p/840817/highlight/true#M68253It turns out that one can just about draw a couple of characters of text in some tiny font, in the 1msIn reality one could draw a lot more if the text drawn ends up well away from where the video RAM is being read out. So it would be highly application dependent.

author: Nominal Animal
author_rank: Super Contributor
timestamp: September 19, 2025, 08:50:36 pm
content: ILI4988 and most other similar controllers do support command 0x45Read Scan Line, which tells you where the physical update is right now. These controllers usually update an entire scan line at a time due to the transistor driver structure they use (which is also why scan lines tend to be across the shorter direction, opposite to most CRTs and similar).That is, when you start drawing a glyph, you could check if the physical update is far enough from the update region, and make a decision whether to draw now or wait until the update passes the region (by e.g. reprogramming the TE trigger and using an interrupt on that one, or polling command 0x45).

author: peter-h
author_rank: Super Contributor
timestamp: September 19, 2025, 09:20:05 pm
content: That could also get really messyImagine maintaining a product where somebody did that.FWIW, syncing stuff to TE does no harm even if it overruns ridiculously, like my clock which takes 2.5 frames to draw.

author: Nominal Animal
author_rank: Super Contributor
timestamp: September 20, 2025, 12:16:04 am
content: Quote from: peter-h on September 19, 2025, 09:20:05 pmIt would only make sense if it was the only thing moving in the display almost all of the time; say a navigation arrow or dot, or something similar.Ignoring TE completely does no lasting harm either, at most visible tearing (partially old and partially new data displayed).I consider it much less of a problem than say flickering.In my use cases, I use a lot of animation — closer to games than data-packed status displays! — and tearing there is a much bigger issue than say when updating some numbers or text: it kinda-sorta defeats the purpose of using the animation in the first place (overcoming non-technical humans' assumptions). If you have scrolling text, then tearing does cause similar difficulty to reading as noise or slight flickering would. Thus, it really depends on what the display is showing and what is changing; it is almost impossible to make an "universal" library that would Just Work for all use cases equally. Which is why I keep a lot of different options in my proverbial software solution toolbox, to choose from as appropriate for each use case.

author: peter-h
author_rank: Super Contributor
timestamp: September 20, 2025, 05:05:05 pm
content: I've spent a lot more time on this tearing effect business today. It works pretty well, notwithstanding some unexplained ISR priority/FreeRTOS interactionhttps://www.eevblog.com/forum/microcontrollers/freertos-and-using-an-isr-to-unsuspend-a-suspended-task-(32f417)/I can also see usingsuspend_wait_for_TE()osDelay(x)draw graphicswhere x can be 1 to 18 where 18ms is the frame duration, to tweak the graphics drawing point, relative to the current video RAM reading point (which can be established easily enough if you have the TE pulse to start on).AFAICT if using the LCD in landscape, the refresh will be L-R or R-L rather than vertically.If I was doing this again I would go parallel. Even 8 bits wide is far faster than SPI. This was a compromise decision on the 100 pin QFP package and pin allocation to get four serial ports, ETH, USB, 2xSPI. I don't regret it because the SPI interface, 15MHz for the 320x480, is absolutely fine for any industrial application I might get, but it is a lesson.