cancel
Showing results for 
Search instead for 
Did you mean: 

TouchGFX on Custom Board with no TE pin

Iris-DM
Associate III

I have a custom board, which uses STM32H747IXH6 and MB1166 LCD screen from the related discovery board. I am trying to get TouchGFX up and running on this custom setup, but in my PCB design, I missed out the dedicated TE pin in the connector (I'm following the RaspberryPi DSI convention of DSI CLK, Data Lanes and I2C only). I can initialise the display, but I cannot get my TouchGFX application running. The process at the moment is as follows:

Init DSI Host

Reset the LCD display
Config DSI PLL
Config Host Timeouts
Config PHY Timers
Config LPCommand
Config AdaptedCommand Mode
Invert clock and data pins (to correct for PCB error)
Register busIO for OTM8009A
Init OTM8009A (as per Discovery examples)
Config Flow Control
Force RX Low Power

Init LTDC

Active low VSYNC and HSYNC polarity
803x483 total width and height (800x480 + porches)
Format RGB888
Double frame buffer
Start address 0xD0000000

Init FMC (IS42S32800J)
Init as Bank 2

Init TouchGFX

Start TouchGFX Thread 

 

Now when TouchGFX starts, taskEntry sits at OSWrappers::waitForVSync(); I assume that this VSync should be called from HAL_DSI_TearingEffectCallback in TouchGFXHAL, but this callback never fires. It appears a tearing effect is requested earlier in taskEntry by LCD_ReqTear, which in the discovery code writes OTM8009A_CMD_TEEON to the LCD driver. I have modified LCD_ReqTear to send OTM8009A_CMD_WRTESCN with a param of 533 (0x2,0x15) instead, as per the CMDMode_TearingEffect example, but the TearingEffectCallback is still not triggered.

What am I missing here? I can't attach the full project for confidentiality reasons, but I'm happy to share main.c and TouchGFXHAL.cpp 

I'm aware also that TearingEffectCallback and EndOfRefreshCallback still contain code that assumes the display is split in two (as per both the examples I have borrowed from), I wouldn't have thought this was the issue however, as neither of these callbacks ever fire.

Edit

I have updated taskEntry to enable the DSI interrupts and call a DSI_Refresh before the first wait for Vsync, but the  callbacks still don't fire. Examining the SFRs shows that the DSI transfer hangs on BUSY (DSI_WISR), so presumably the callback doesn't fire due to the refresh never finishing. What could be preventing the transfer from occurring?

1 ACCEPTED SOLUTION

Accepted Solutions
Iris-DM
Associate III

Sorted! I got it working with the example and then copied the TouchGFXHAL code to my custom project. The colours are wrong, but we're off to a good start!

View solution in original post

17 REPLIES 17
Iris-DM
Associate III

Post updated to add more information

Iris-DM
Associate III

Update:

I have moved the OTM8009A initialisation code to the end of the LTDC initialisation routine. The general flow is now:

Reset LCD via GPIO
Init DSI
Init LTDC
Start DSI
Init OTM8009A via DSI
Modify DSI flow control & low power RX 
Request scan

uint8_t ScanLineParams[2];
uint16_t scanline = 500;
ScanLineParams[0] = scanline >> 8;
ScanLineParams[1] = scanline & 0x00FF;

HAL_DSI_LongWrite(&hdsi, 0, DSI_DCS_LONG_PKT_WRITE, 2, 0x44, ScanLineParams);
HAL_DSI_ShortWrite(&hdsi, 0, DSI_DCS_SHORT_PKT_WRITE_P1, OTM8009A_CMD_TEEON, 0x00);

Turn the display on and call a refresh

HAL_DSI_ShortWrite(&hdsi,0,DSI_DCS_SHORT_PKT_WRITE_P0,OTM8009A_CMD_DISPON,0x00);
HAL_DSI_Refresh(&hdsi);

Then start the TouchGFX task

HAL_DSI_EndOfRefreshCallback is now called once, but no tearing effect callback is generated, thus VSync does not fire and TouchGFX doesn't take over the management of the process. Based on AN46860, I have enabled the bus turnaround request and the tearing effect acknowledge request.

mathiasmarkussen
ST Employee

I'm not sure where this goes wrong, but I can try to explain what I would do in this case, maybe there is a missing step somewhere in that process.

First, since you should now be getting TE signals on the bus rather than on a GPIO, set that under DSIHOST in CubeMX:

DSIHOST.png

Now,when your DSI interrupt fires, it should be able to determine if a TE signal has been received:DSIIRQHANDLER.png

HAL_DSI_TearingEffectCallback() is weak, so you can define that yourself, which it seems from what you write is already done in TouchGFXHAL.

TECALLBACK.png

Are you still running adapted command mode, or are you in video mode?

Have you looked at the code that split the display in two? I get that that can be a very confusing solution, but what basically happens is that the LTDC frame buffer pointer is moved, and then an LTDC transfer to the screen is triggered. If a transfer is never triggered, I'm not sure there would be a callback, but I'm not sure wether you actually ever get to that point?

Iris-DM
Associate III

I'm definitely running in adapted command mode, yes. I've also worked out how the code that splits the display in two works and have adapted my DSI EOR callback and LTDC setup to match.

At the end of my peripheral init (User code 2 in main), I call the following

HAL_DSI_Stop(&hdsi);

	DSI_LPCmdTypeDef LPCmd = {0};
	LPCmd.LPGenShortWriteNoP = DSI_LP_GSW0P_ENABLE;
	LPCmd.LPGenShortWriteOneP = DSI_LP_GSW1P_ENABLE;
	LPCmd.LPGenShortWriteTwoP = DSI_LP_GSW2P_ENABLE;
	LPCmd.LPGenShortReadNoP = DSI_LP_GSR0P_ENABLE;
	LPCmd.LPGenShortReadOneP = DSI_LP_GSR1P_ENABLE;
	LPCmd.LPGenShortReadTwoP = DSI_LP_GSR2P_ENABLE;
	LPCmd.LPGenLongWrite = DSI_LP_GLW_ENABLE;
	LPCmd.LPDcsShortWriteNoP = DSI_LP_DSW0P_ENABLE;
	LPCmd.LPDcsShortWriteOneP = DSI_LP_DSW1P_ENABLE;
	LPCmd.LPDcsShortReadNoP = DSI_LP_DSR0P_ENABLE;
	LPCmd.LPDcsLongWrite = DSI_LP_DLW_ENABLE;
	LPCmd.LPMaxReadPacket = DSI_LP_MRDP_ENABLE;
	LPCmd.AcknowledgeRequest = DSI_ACKNOWLEDGE_DISABLE;
	if (HAL_DSI_ConfigCommand(&hdsi, &LPCmd) != HAL_OK)
	{
		Error_Handler();
	}

	HAL_DSI_Start(&hdsi);

        uint8_t ScanLineParams[2];
	uint16_t scanline = 500;
	ScanLineParams[0] = scanline >> 8;
	ScanLineParams[1] = scanline & 0x00FF;

	HAL_DSI_LongWrite(&hdsi, 0, DSI_DCS_LONG_PKT_WRITE, 2, 0x44, ScanLineParams);
	//HAL_DSI_ShortWrite(&hdsi, 0, DSI_DCS_SHORT_PKT_WRITE_P1, OTM8009A_CMD_TEEON, 0x00);

	HAL_DSI_ShortWrite(&hdsi,
			0,
			DSI_DCS_SHORT_PKT_WRITE_P0,
			OTM8009A_CMD_DISPON,
			0x00);

	HAL_DSI_Refresh(&hdsi);

Then go on to start the touchGFX task as per usual. I would have thought this command would have generated a TE on the DSILink via the Refresh call, which I believe kicks off the LTDC transfer. As touchGFX has not started at this point, I'd expect to just see the random noise of the uninitialised buffer on screen (which I do), but still no TE interrupt generated.

Interestingly, as soon as I call DSI_Start, the GPRDE bit is set in the DSI ISR1 register. Could this be an indicator for something? I also get constant LTDC interrupts with no flags in the LTDC ISR, so I assume this is cause by GPRDE.

The reference manual for H747 has this detail about the GPRDE bit:

REFMAN.png

In the original TouchGFX project, the LTDC is turned off when the DSI_Start command is called. It may lead to some undefined behaviour if the DSI is in the middle of a transfer when the DSI host starts up, so I would try to call

__HAL_LTDC_DISABLE(&hltdc) before starting DSI and __HAL_LTDC_ENABLE(&hltdc) after.

You might also have noticed that there is a 1 ms delay in the original HAL_DSI_EndOfRefreshCallback. I do not actually know why it is there, but I do know that the whole thing stops working if it is removed. My guess is that it ensures that the DSI bus or LTDC is ready for the modification that will happen because of the half-screen thing, so you could also just try to add a delay before starting the DSI host.

I've made progress, but still no complete working solution. I'm now using a timer to trigger vsync every 20ms from main:

IrisDM_0-1731581952695.png

When my code launches, the first framebuffer is written to the LCD. This is done by forcing a DSI Refresh from TouchGFXHAL::taskEntry(). The refresh that writes to the screen is on line 154.

IrisDM_1-1731582037343.png

This is fine, so long as my display is static. We get through backPorchExited() and go into the infinite loop, checking for vsync - although nothing ever actually changes in the framebuffer as there's nothing new to display.

If the framebuffer needs to be updated, either through user code in the view or putting an animated image in the display, the first refresh draws the initial framebuffer, but backPorchExited() never returns, it gets stuck on Model::Tick().

I have to assume that there is an issue with the updating of the framebuffer. Its address is allocated in CubeMX - does this need manually setting in TouchGFXHAL::initialize()?

IrisDM_2-1731582355937.png

And DMA2D is configured with a matching format

IrisDM_3-1731582385940.png

We're using external SRAM here, but FMC is configured and correctly as I can see the framebuffer in the memory monitor

IrisDM_4-1731582815757.png

What other issues could cause the hang when copying the new framebuffer? 

 

 

Furthermore, I can see that TouchGFXHAL::endFrame() and therefore flushFrameBuffer() are never called

The stack trace when the task hangs is as follows

IrisDM_0-1731586494519.png

Could it be something to do with the DCache issues on STM32H7 devices?

mathiasmarkussen
ST Employee

One thing that could lead to the tick method hanging is trying to measure MCU usage but not having the correct hooks in the OS to support this.

Do you have a call to enableMCULoadCalculation(true) somewhere? I believe removing that (or setting it to false in TouchGFXHAL::initialize()) would solve the problem so TouchGFX can execute.

I would advise using double buffers if you have space for that in RAM. In general, it is easier to have their address set by allocation than by manual address.

If set to by allocation, you can define what sector they go in with the linker script, you can see how that is handled for your particular compiler in most of the board setups that ship with the TouchGFX designer.

As you set it by address, it will be placed at that address.

You can see what the start address of the currently active framebuffer is in the LTDC->CFBAR register.

But with single frame buffer and no TE signal to synchronize, I would expect tearing on the display when anything moves.