cancel
Showing results for 
Search instead for 
Did you mean: 

Running TouchGFX on STM32F2 series MCU

JBoec.1
Associate II

Hi,

I need al little help running TouchGFX to a STM32F207VG MCU. We already have a custom board featuring this MCU and a touchscreen with an ILI9341 driver IC. The screen communication is done using the FSMC on the MCU. I've got code working to write data to the framebuffer integrated into the screen and I also tried a couple of examples on Discovery boards featuring other MCUs.

Now I want to combine these. I quickly realized that code generation for TouchGFX is not supported in CubeMX for this chip. Can I just generate a gui and add it to a project generated with CubeMX and manually add my driver code? Or is there another way?

Thanks in advance!

12 REPLIES 12
Alexandre RENOUX
Principal

Hello,

Yes I believe you can definitely do that. And you can refer to an already made application template available in the Designer such as the F412-DISCO, F429-DISCO or G071-NUCLEO.

Don't forget to write your code in USER CODE SECTION when you need to modify files generated by CubeMX.

/Alexandre

JBoec.1
Associate II

Hello,

thank you for your answer. So far, I tried the following, all with help from the CubeIDE:

I created an application (1) targeting the STM32F207VG and set up FreeRTOS, CRC and the FSMC for the display

I created an application (2) targeting the STM32F407VG and added TouchGFX and FreeRTOS.

0693W000004K0b8QAC.png 

In TouchGFX Designer, I simply added a button and created code.

I then tried copying the TouchGFX and Middleware/ST from application 2 to apllication 1. I added the include paths to the C and C++ sections in application 1 and libtouchgfx.a from the core_m4f/gcc folder. I then had to exclude the Middlewares/ST/TouchGFX folder from building. Is this correct?

0693W000004K0d4QAC.png0693W000004K0gSQAS.png 

I then tried to implement the methods described in the TouchGFXHAL.cpp, so touchgfxDisplayDriverTransmitActive() and touchgfxDisplayDriverTransmitBlock().

Now I am stuck at two problems. In TouchGFXGeneratedHAL.cpp the method DisplayDriverTransmitBlock(...) is being called in flushFrameBuffer(...), but only touchgfxDisplayDriverTransmitBlock is defined as extern "C". Is this an error in the generated file? The second error is an undefined reference to touchgfx::OSWrappers::signalRenderingDone(). I made shure that the corresponding cpp file is being compiled, but the error continues.

0693W000004K0m6QAC.png0693W000004K0mQQAS.pngDid I miss something? Are the includes correct?

Thank you again,

Jonas

YIzAKat
Associate II

Hi,

Looks like there has been no activity on this post for 21 days but I too am seeing both these problems using an SPI partial buffer strategy.

Adding touchgfx prefix to the mismatched name will fix the DisplayDriverTransmitBlock() problem however that then results in the undefined reference that Jonas has encountered.

This is re-using UI code which was previously working for a project built using 4.14.

Anybody got any ideas on this? In the meantime I've reverted to 4.14 on this new project. But since it uses a partial frame buffer strategy I'd rather like to make use of whatever improvements have been made as mentioned in the release notes.

As an aside, I use RTOS for this project and had to remove and re-add the RTOS middleware package in Cube after adding touchGFX package to repair some missing include paths.

Thanks,

Jason.

MR1
Associate

Hi

I´m receiving same errors when configuring partial buffer mode with touchgfx 4.15.0 with STM32F4

Have you found any other solution appart from using previous version?

Thanks in advance

ALomb
Senior

Hi,

I have the same problem too: undefined reference to `touchgfx::OSWrappers::signalRenderingDone()' in TouchGFXGeneratedHAL.cpp

My hardware is X-NUCLEO-GFX01M1 and NUCLEO-G071RB that @Alexandre RENOUX​ mentioned in the previous answer.

Starting from the application template supplied with TouchGFX Designer 4.15.0 I added FreeRTOS and I don't know how to solve the problem.

Surely an application template with FreeRTOS support would be very handy :grinning_face:

Best Regards

Alexandre RENOUX
Principal

Hello,

This is an known issue that will be fixed in the next release 4.16 coming out end of this year.

The signalRenderingDone() function is not implemented correctly. To solve manually this issue, simply add the following code to your OSWrappers.cpp

/*
* Signal that the rendering of the frame has completed. Used by
* some systems to avoid using any previous vsync.
*/
 
void OSWrappers::signalRenderingDone()
{
    osMessageQueueReset(vsync_queue);
}

Very sorry for the inconvenience.

Adding FreeRTOS to a project using Partial Framebuffer should be straightforward. Without this issue of course ^^

The reason why we do not use FreeRTOS in the Application Template for G071RB-NUCLEO is because of the limited RAM.

/Alexandre

ALomb
Senior

Hello @Alexandre RENOUX​ ,

thanks for the fix. I applied it, but a HardFault occurs when waitForVSync() is called during TouchGFXHAL::initialize() in TouchGFXHAL.cpp

Through the STM32CubeMX I added support for the FreeRTOS (CMSIS_V2) and modified the StartDefaultTask in maic.c file as follows:

/* USER CODE END Header_StartDefaultTask */
void StartDefaultTask(void *argument)
{
	/* USER CODE BEGIN 5 */
	MX_TouchGFX_Process();
	/* USER CODE END 5 */
}

I suppose I have to change more, both in initialization and in the run phase. Can you provide us with guidelines to do this?

I have thoroughly read the "Lowering Memory Usage with Partial Framebuffer" and "TouchGFX on Low Cost Hardware" documentation, but I still miss something.

How to manage TE with FreeRTOS?

In the application tamplate for X-NUCLEO-GFX01M1 and NUCLEO-G071RB the Tearing Effect signal is an interrupt managed in the rising and falling edge.

I don't understand how it is handled together with TIM6 and in the functions TouchGFXHAL::beginFrame and TouchGFXHAL::endFrame.

could you kindly help me understand?

how does the touchgfxDisplayDriverShouldTransferBlock function work ?

Best Regards

Antonello

Hello @Community member​ , I also have these same questions and so happy you've asked them. Here is where I am. I've re-written the MB1642B files to be more RTOS friendly. Using semaphores instead of variables.

int touchgfxDisplayDriverTransmitActive(void)
{
  return (osSemaphoreGetCount(DISPLAY_SEMAPHOREHandle) == 0) ? 1 : 0;
}

Little things like that.

In the original MB1642_ReadDMA_Data function it writes back the same thing that was just read. Any reason why?

I re-wrote it to just be read only.

void MB1642B_ReadDMA_Data(uint32_t address24, uint8_t* buffer, uint32_t length)
{
	uint8_t cmd[4] = { CMD_READ,
					   ((address24 >> 16) & 0xFF),
					   ((address24 >>  8) & 0xFF),
					   (address24 & 0xFF)
					 };
 
	// 1. Aquire semaphore
	while( osSemaphoreAcquire(FLASH_SEMAPHOREHandle, 100) != osOK )
	{
		osDelay(100);
	}
	// 2. Pull CS Line
	DATAREADER_CS_LOW();
	// 3. Transmit Read Request with address
    if( HAL_SPI_Transmit( &hspi2, cmd, 4, 100 ) != HAL_OK )
    {
    	Error_Handler();
    }
    // 4. Read from Flash from DMA
    if( HAL_SPI_Receive_DMA( &hspi2, buffer, length ) != HAL_OK )
    {
    	Error_Handler();
    }
}

I'm at the point where I need to know where the touchgfxDisplayDriverShouldTransferBlock function implementation should be. This is the original:

int touchgfxDisplayDriverShouldTransferBlock(uint16_t bottom)
{
  //return (bottom < getCurrentLine());
  return (bottom < (TE > 0 ? 0xFFFF : ((__IO uint16_t)htim7.Instance->CNT)));
}

I'm using timer 7 instead of 6, but still don't understand its meaning.

I have the TE interrupt handled by a callback:

void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
  if (GPIO_Pin == DISPLAY_TE_INT_Pin)
  {
	  if( HAL_GPIO_ReadPin( DISPLAY_TE_INT_GPIO_Port, DISPLAY_TE_INT_Pin ) == GPIO_PIN_SET )
	  {
		  TE++;
		  (&htim7)->Instance->CR1 &= ~(TIM_CR1_CEN);
		  (&htim7)->Instance->CNT = 0;
		  touchgfxSignalVSync();
	  }
	  else
	  {
		  (&htim7)->Instance->CR1 = (TIM_CR1_CEN);
	  }
  }
}
 
void HAL_SPI_TxCpltCallback(SPI_HandleTypeDef *hspi)
{
   MB1642B_Display_Driver_DMACallback();
}
 
void HAL_SPI_RxCpltCallback(SPI_HandleTypeDef *hspi)
{
	MB1642B_Read_Data_DMACallback();
}

Hello @Community member​ 

TIM6 is used to simulate the display refresh line. This way the MCU knows at any given time at what line is the display currently refreshing. This is to avoid Tearing Effect. But this has nothing to do with the Tearing Effect callback which is an external interrupt that should not be impacted by whether you have FreeRTOS or not.

Receiving the Tearing Effect interrupt will trigger a new rendering. That is all. Then a new rendering means that a beginFrame() and later an endFrame() will be called.

"I suppose I have to change more, both in initialization and in the run phase."

No you should not need to change much.

I'll try to have a look and add FreeRTOS on my side and I will come back to you.

/Alexandre