cancel
Showing results for 
Search instead for 
Did you mean: 

Diagonal tearing on LCD_DSI_VideoMode_DoubleBuffering on STM32F469I-DISCO DK32F469I$AU

Richard-CRT
Associate III

[If this would be better off in one of the other STM32 MCUs sub-forums, please feel free to move it admins]

I have spent a very long time removing the BSP initialisation calls from the LCD_DSI_VideoMode_DoubleBuffering example on STM32F469I-DISCO, however it behaves exactly the same using the "stock" example and with my modifications. I am not using TouchGFX.

The symptom is a consistent diagonal tear in a fixed location on my landscape configured display regardless of where the region of the screen I am editing is. Naturally, if the region I'm editing doesn't cross the diagonal, the tear isn't visible. Slow mo video of issue is attached.

In both the example and my modified code, the screen is waiting on HAL_LTDC_LineEventCallback to switch to a new buffer like so:

RichardCRT_0-1714667465849.png

In my modified code as shown above, Buffers[front_buffer] is written to (using DMA2D) while the state machine is at the state before BufferPrepared, and then the state machine moves on to BufferPrepared 200ms later (same behaviour when this is much higher). 200ms allows the DMA2D plenty of time to complete, so when the interrupt above fires with the buffer state correctly set the data should be stable and unchanging.

So in summary, I have 2 buffers in SDRAM. The DMA2D is only ever writing to the one that the LTDC is not reading. And there's a significant enough delay between the DMA2D operation and the LTDC swapping buffers that the DMA2D must have completed in time. So why does the display end up displaying half (not exactly half, but whatever) of the old buffer and half of the new buffer, split by a diagonal line?

The first of the previous tickets below indicates that this is caused by the screen updating in a 'portrait' manner while the LTDC is updating in a 'landscape' manner, but I don't fully understand this, and neither did the OP of that question (@S.K.Matters), but they never received any further explanation. What's more, even if that is an explanation of the issue, why has the LCD_DSI_VideoMode_DoubleBuffering example got this issue?

The second of the previous tickets below has the same issue, complete with a similar video, but received no reply. I'm hoping someone will be able to reply to this one.

The last ticket I have linked from just a few days ago refers to the same exact issue on a different DISCO board (STM32H747I-DISCO) and the ST employee there said he has reported it internally.

 

Previous tickets going back 5 years ago with seemingly the same issue but no solution:

https://community.st.com/t5/stm32-mcus-touchgfx-and-gui/some-kind-of-tearing-effect-with-lcd-dsi-videomode/td-p/398477

https://community.st.com/t5/stm32-mcus-touchgfx-and-gui/stm32f469i-disco-screen-tearing-on-double-buffer-example/m-p/668979#M37372

Previous ticket with seemingly the same issue on a different dev board and a ST employee saying the issue was "reported":

https://community.st.com/t5/stm32-mcus-products/stm32h747i-disco-tearing-in-double-buffering/m-p/647508#M237425

 

23 REPLIES 23
Alekseus
Associate II

Conducted some experiments and couldn't find satisfying results. It's possible to kick out the diagonal tear line off the screen by significantly increasing Vertical back porch (150 -> 900) but picture becomes flickering.

Also you can change a refresh order using MADCTL register but anyway the tear line is still there just rotated by 90 deg.

Seems like the only option is just draw everything rotated 90 deg or replace the display by the one that can refresh a picture along the shorter side. Changing X-Y axes in LTDC could help but I can't see such option.

Still can't get why the tear line is 45 deg diagonal (is refreshing rate comparable to write rate?) and why it is almost center aligned (disregarding refresh order).

And I noticed that it is possible to bypass GRAM but it looks a bit difficult as requires display board modification (RGBBP pin) and there's no guarantee that it would help.

Try locate trouble by little steps. Start with DSI pattern generator tests Hal have calls for this.

Next test is single buffer LTDC...  16bit vs 24bt vs L8...

Richard-CRT
Associate III

For what it's worth, I got a reply from ST on my engineering support ticket that @Tesla DeLorean recommended I submit. They don't think this is a configuration issue, and that the only landscape option with this LCD is the partial refresh command-mode approach (which I note does improve performance, but as they said, does not completely eliminate tearing effects, only helps). Unfortunately command-mode isn't an option for me with my current project aspirations. See full reply:

 


LCD screen on STM32F469-DISCO board is not adapted for landscape mode. It will scan vertically (horizontal scanning is not available), This is why you have diagonal tearing effect when configured in landscape mode.

One solution we would recommend is to used command mode partial refresh strategy, this will help to avoid tearing effect.
You can refer to example available in STM32CubeFW_F4 package available also on github.com: https://github.com/STMicroelectronics/STM32CubeF4/tree/master/Projects/STM32469I-Discovery/Examples/LCD_DSI/LCD_DSI_CmdMode_PartialRefresh

 

Thanks. Tried the pattern generator and ended up with the same thing. So testing LTDC etc is pointless.

As @Richard-CRT mentioned, the display "is not adapted for landscape mode" (but come on, the same display is used with at least THREE boards and there's a double buffer video mode example project created specially for these boards! How come!).

I'm still curious how it could be "adapted" and why the display IC allows to change orientation whereas there's an obvious tearing effect if we do such a change.

When pattern gen show same , you locate issue to chip and DSI config. For example my used displays for change config require around 70 changes in display registers...

And when i good rememmber 469 disco have many releases with around 3 different displays ...

Examples provided isnt guarant 100% working...

You are right, the issue is located but I can't see any option not for chip nor for DSI to change. That display chip (NT35510) requires only 3 registers to be updated (MADCTL, CASET and RASET; or even one if the latter two are equal) to change orientation.

Richard-CRT
Associate III

Bearing in mind I can't verify how the OTM8009A driver on the older revisions behaves:

It feels to me like the most likely explanation is that the display on the original revision(s) of these board(s) had a better driver chip (certainly the OTM8009A has much lower porch values than the NT35510, not that that necessarily has anything to do with this), and the examples were made for that board. Then, the obsolescence or cost-down process or whatever the driving factor behind the NT35510 revision overlooked the fact that the replacement display driver doesn't work well in landscape video-mode


@Richard-CRT wrote:

certainly the OTM8009A has much lower porch values than the NT35510


And what is strange, Linux driver for the same display shows ten times smaller values for vertical axis:

static const struct nt35510_config nt35510_frida_frd400b25025 = {
	.width_mm = 52,
	.height_mm = 86,
	.mode = {
		.clock = 23000,
		.hdisplay = 480,
		.hsync_start = 480 + 34, /* HFP = 34 */
		.hsync_end = 480 + 34 + 2, /* HSync = 2 */
		.htotal = 480 + 34 + 2 + 34, /* HBP = 34 */
		.vdisplay = 800,
		.vsync_start = 800 + 15, /* VFP = 15 */
		.vsync_end = 800 + 15 + 12, /* VSync = 12 */
		.vtotal = 800 + 15 + 12 + 15, /* VBP = 15 */
		.flags = 0,
	},

But if you try these values the display won't show anything. At the same time the clock value is slightly lesser.

As you see is portrait config and for DSI horizontal part need calculated values, not copy front porch, sync, backporch in DSI setup... Show how you use this values in LTDC and DSI.

I did not copy these values. All these are as they came by default in that example. Setup is like following:

 

/**
  * @brief  NT35510_480X800 Timing parameters for Portrait orientation mode
  */
#define  NT35510_480X800_HSYNC             ((uint16_t)2)      /* Horizontal synchronization */
#define  NT35510_480X800_HBP               ((uint16_t)34)     /* Horizontal back porch      */
#define  NT35510_480X800_HFP               ((uint16_t)34)     /* Horizontal front porch     */

#define  NT35510_480X800_VSYNC             ((uint16_t)120)      /* Vertical synchronization   */
#define  NT35510_480X800_VBP               ((uint16_t)150)     /* Vertical back porch        */
#define  NT35510_480X800_VFP               ((uint16_t)150)     /* Vertical front porch       */

__weak HAL_StatusTypeDef MX_DSIHOST_DSI_Init(DSI_HandleTypeDef *hdsi, uint32_t Width, uint32_t Height, uint32_t PixelFormat)
{
  /* Timing parameters for all Video modes */
  /*
  The lane byte clock is set 62500 Khz
  The pixel clock is set to 27429 Khz
  */
  if(Lcd_Driver_Type == LCD_CTRL_NT35510)
  {
    VidCfg.HorizontalSyncActive = (NT35510_480X800_HSYNC * 62500U)/27429U;
    VidCfg.HorizontalBackPorch = (NT35510_480X800_HBP * 62500U)/27429U;
    VidCfg.HorizontalLine = ((Width + NT35510_480X800_HSYNC + NT35510_480X800_HBP + NT35510_480X800_HFP) * 62500U)/27429U;
    VidCfg.VerticalSyncActive = NT35510_480X800_VSYNC;
    VidCfg.VerticalBackPorch = NT35510_480X800_VBP;
    VidCfg.VerticalFrontPorch = NT35510_480X800_VFP;
  }
...
__weak HAL_StatusTypeDef MX_LTDC_Init(LTDC_HandleTypeDef *hltdc, uint32_t Width, uint32_t Height)
{
  if(Lcd_Driver_Type == LCD_CTRL_NT35510)
  {
    hltdc->Init.HorizontalSync     = NT35510_480X800_HSYNC - 1;
    hltdc->Init.AccumulatedHBP     = NT35510_480X800_HSYNC + NT35510_480X800_HBP - 1;
    hltdc->Init.AccumulatedActiveW = NT35510_480X800_HSYNC + Width + NT35510_480X800_HBP - 1;
    hltdc->Init.TotalWidth         = NT35510_480X800_HSYNC + Width + NT35510_480X800_HBP + NT35510_480X800_HFP - 1;
    hltdc->Init.VerticalSync       = NT35510_480X800_VSYNC - 1;
    hltdc->Init.AccumulatedVBP     = NT35510_480X800_VSYNC + NT35510_480X800_VBP - 1;
    hltdc->Init.AccumulatedActiveH = NT35510_480X800_VSYNC + Height + NT35510_480X800_VBP - 1;
    hltdc->Init.TotalHeigh         = NT35510_480X800_VSYNC + Height + NT35510_480X800_VBP + NT35510_480X800_VFP - 1;
  }
...

 

All I did - just changed mentioned registers (MADCTL, CASET, RASET) and swapped width and height. It works normally in both orientations except diagonal tearing in landscape orientation.

Also I tried to swap horizontal and vertical values (sync, porches) but in that case the display shows nothing. If the values has to be recalculated I can't see any clue how to do it. But it seems it shouldn't be swapped.