Skip to main content
Krautermann
Senior
June 27, 2023
Solved

How to execute a function in main.c instead of model.cpp?

  • June 27, 2023
  • 4 replies
  • 5763 views

I am using the STM32H745XIH6 board with touchgfx. And I am calling the HAL_UART_Transmit_DMA function in model.cpp whenever the user entered a string on the LCD.

But I would like this HAL_UART function to be execute to main.c instead. How do I do this codewise? I am not very experienced with interacting C++ with C. The function that I want to transfer to main.c is SendData2MCU(int UART, int DMA, uint8_t* data)

 

#include <gui/model/Model.hpp>
#include <gui/model/ModelListener.hpp>

#ifndef SIMULATOR
#include "main.h"
#include "string.h"
extern "C"
{
	extern UART_HandleTypeDef huart1;
	extern UART_HandleTypeDef huart3;
	extern UART_HandleTypeDef huart7;
	extern uint8_t RX1_String_cpy[512];
	extern uint8_t RX3_String_cpy[512];
	extern uint8_t RX7_String_cpy[512];
	extern int DMA_complete;
}
#endif

Model::Model() : modelListener(0), toggleGreenLEDButtonState(false), toggleRedLEDButtonState(false)
{

}

void Model::tick()
{
#ifndef SIMULATOR
	modelListener->RX1_3Data((char*) RX1_String_cpy, (char*) RX3_String_cpy);
	modelListener->RX7_Data((char*) RX7_String_cpy);
	modelListener->klima_sim_receive((char*) RX1_String_cpy);
#endif
}

// The following code needs to be executed in main.c
void Model::SendData2MCU(int UART, int DMA, uint8_t* data)
{
#ifndef SIMULATOR
	if(UART==0)
	{
		if(DMA==0)
		{
			HAL_UART_Transmit(&huart3, (uint8_t*) data, strlen((char*)data)-2, 100);
		}
		else if(DMA==1)
		{
			DMA_complete = 0;
			HAL_UART_Transmit_DMA(&huart3, (uint8_t*) data, strlen((char*)data)-2);
			while(DMA_complete == 0){};
		}
	}
	if(UART==1)
	{
		if(DMA==0)
		{
			HAL_UART_Transmit(&huart1, (uint8_t*) data, strlen((char*)data), 100);
		}
		else if(DMA==1)
		{
			DMA_complete = 0;
			HAL_UART_Transmit_DMA(&huart1, (uint8_t*) data, strlen((char*)data));
			while(DMA_complete == 0){};
		}
	}
#endif
}

 

The reason for this is, DMA has been shown to not be working reliably when compiled in C++. I have been told that the compiler can convert C directly to assembly language but for C++, it has to be translated into another form first and this therefore causes unreliability. 
 

This topic has been closed for replies.
Best answer by MM..1

Seems you are complete lost in noOS vs RTOS implement and too with DMA offload and callbacks.

In model or any other part of touchGFX thread you cant wait for complete any operations . Nonsense is wait 100ms or while ()

Exceptions is very quick operations for example less as 1ms SPI usw.

Next nonsense is on every tick call

 

 

modelListener->RX1_3Data((char*) RX1_String_cpy, (char*) RX3_String_cpy);
...

 

 

This require check if new value exist ...

Primary your DMA_complete need volatile and right usage is protect next send not wait actual 

 

volatile uint8_t DMA_complete = 1;
...

while(DMA_complete == 0){};
HAL_UART_Transmit_DMA(&huart1, (uint8_t*) data, strlen((char*)data));
DMA_complete = 0;

and for your question remove senddata2 functions from model and presenter too. Create one in main.c and include prototype in view.cpp, call it directly .

 

4 replies

redmig
Associate III
June 27, 2023

Use a queue to send the data to the task you want.

if the string is a long one, pass the pointer to the data, keeping in mind to preserve the data you are pointing until you consume it. You can start from here: 

https://support.touchgfx.com/docs/development/ui-development/touchgfx-engine-features/backend-communication

Have fun!

 

Krautermann
Senior
June 28, 2023

I forgot to mention, I am NOT using RTOS!

The link you provided - I have already read that but in my case I am not using RTOS to call my function.

I know how to parse data from main to model by using the extern C but how do I parse data from model to main?

redmig
Associate III
June 28, 2023

You already have your strings defined as extern..

 

extern uint8_t RX1_String_cpy[512];
extern uint8_t RX3_String_cpy[512];
extern uint8_t RX7_String_cpy[512];

 

Where is the actual definition? if it is in main just use them from there..

redmig
Associate III
June 28, 2023

I might miss something.. but define your pointer to the buffer in main and export it to the model.

from the model fill your buffer with data.. and you have it in the main. or not?

Krautermann
Senior
June 28, 2023

touchgfxmodel.PNG

I have added a picture which represents how touchgfx LCD works with the backend module (main.c). The text in red is what's missing for me. I do not know how to send the function SendData2MCU from model.cpp to main.c file.

What should I write? main->SendData2MCU ?? This does not work...

MM..1
MM..1Best answer
Chief III
June 28, 2023

Seems you are complete lost in noOS vs RTOS implement and too with DMA offload and callbacks.

In model or any other part of touchGFX thread you cant wait for complete any operations . Nonsense is wait 100ms or while ()

Exceptions is very quick operations for example less as 1ms SPI usw.

Next nonsense is on every tick call

 

 

modelListener->RX1_3Data((char*) RX1_String_cpy, (char*) RX3_String_cpy);
...

 

 

This require check if new value exist ...

Primary your DMA_complete need volatile and right usage is protect next send not wait actual 

 

volatile uint8_t DMA_complete = 1;
...

while(DMA_complete == 0){};
HAL_UART_Transmit_DMA(&huart1, (uint8_t*) data, strlen((char*)data));
DMA_complete = 0;

and for your question remove senddata2 functions from model and presenter too. Create one in main.c and include prototype in view.cpp, call it directly .

 

Krautermann
Senior
June 29, 2023

I removed the function in the Model::tick() now like you said and also removed it from presenter as well. I connected my RX_String array from main to view.cpp as follows:

#include <gui/screen2_screen/Screen2View.hpp>

#ifndef SIMULATOR
#include "stdio.h"
#include "main.h"
#include <cstring>
#include <string>
extern "C"
{
	extern uint8_t RX1_String_cpy[512];
	extern uint8_t RX3_String_cpy[512];
}
#endif


char *temparray[128];
char Datarray[128];
int n;


Screen2View::Screen2View()
{
	gui_keyboard.setPosition(80,16,320,240);
	add(gui_keyboard);
	gui_keyboard.setVisible(false);
	gui_keyboard.invalidate();
}

void Screen2View::setupScreen()
{
 Screen2ViewBase::setupScreen();
}

void Screen2View::tearDownScreen()
{
 Screen2ViewBase::tearDownScreen();
}

void Screen2View::RX1_3Data()
{
	RX_TextArea.setWideTextAction(touchgfx::WIDE_TEXT_WORDWRAP);
	if(UARTToggleButton.getState()==1) //UART 1
	{
		char *ptr = strtok((char*)RX1_String_cpy, ",");
		int i = 0;
		while(ptr != NULL)
		{
			temparray[i] = ptr;
			i++;
			ptr = strtok(NULL, ",");
		}
		n = sprintf(Datarray, "Temp: %s\nHumidity: %s\nMode: %s\nNo. of Alarms:%s\n", temparray[0], temparray[1], temparray[2], temparray[3]);
		Unicode::snprintf(RX_TextAreaBuffer, RX_TEXTAREA_SIZE, Datarray);
	}
	else if(UARTToggleButton.getState()==0) //UART 3
	{
		Unicode::strncpy(RX_TextAreaBuffer, (char*)RX3_String_cpy, RX_TEXTAREA_SIZE);
	}
	RX_TextArea.invalidate();
}

 But I don't see the string appear on the display. It works only when I have it model::tick()

This is my main:

uint8_t RX1_String[512];
uint8_t RX1_String_cpy[512];
uint8_t RX3_String[512];
uint8_t RX3_String_cpy[512];
uint8_t RX7_String[512];
uint8_t RX7_String_cpy[512];

HAL_UARTEx_ReceiveToIdle_DMA(&huart1, RX1_String, sizeof(RX1_String));
HAL_UARTEx_ReceiveToIdle_DMA(&huart3, RX3_String, sizeof(RX3_String));
HAL_UARTEx_ReceiveToIdle_DMA(&huart7, RX7_String, sizeof(RX7_String));

void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t Size)
{
	if(huart==&huart1)
	{
		strncpy((char*)RX1_String_cpy, (char*)RX1_String, sizeof(RX1_String)); //copying to new string because otherwise part of older string will get displayed on LCD
		HAL_UARTEx_ReceiveToIdle_DMA(&huart1, RX1_String, sizeof(RX1_String)); //To enable continuous reception
		memset(RX1_String, '\0', sizeof(RX1_String));
	}
	if(huart==&huart3)
	{
		strncpy((char*)RX3_String_cpy, (char*)RX3_String, sizeof(RX3_String));
		HAL_UARTEx_ReceiveToIdle_DMA(&huart3, RX3_String, sizeof(RX3_String));
		memset(RX3_String, '\0', sizeof(RX3_String));
	}
	if(huart==&huart7)
	{
		strncpy((char*)RX7_String_cpy, (char*)RX7_String, sizeof(RX7_String));
		HAL_UARTEx_ReceiveToIdle_DMA(&huart7, RX7_String, sizeof(RX7_String));
		memset(RX7_String, '\0', sizeof(RX7_String));
	}
}

Why does it only display the string when it is in modelListener?

Krautermann
Senior
June 29, 2023

@MM..1 
I removed the function (modelListener->RX1_3Data((char*) RX1_String_cpy, (char*) RX3_String_cpy);) from model::tick() and also from presenter as per your suggestion. And then I extern the RX_String directly to view. But then I don't see the string being displayed on LCD anymore. Why is that?

#include <gui/screen2_screen/Screen2View.hpp>

#ifndef SIMULATOR
#include "stdio.h"
#include "main.h"
#include <cstring>
#include <string>
extern "C"
{
	extern uint8_t RX1_String_cpy[512];
	extern uint8_t RX3_String_cpy[512];
}
#endif

void Screen2View::RX1_3Data()
{
	RX_TextArea.setWideTextAction(touchgfx::WIDE_TEXT_WORDWRAP);
	if(UARTToggleButton.getState()==1) //UART 1
	{
		char *ptr = strtok((char*)RX1_String_cpy, ",");
		int i = 0;
		while(ptr != NULL)
		{
			temparray[i] = ptr;
			i++;
			ptr = strtok(NULL, ",");
		}
		n = sprintf(Datarray, "Temp: %s\nHumidity: %s\nMode: %s\nNo. of Alarms:%s\n", temparray[0], temparray[1], temparray[2], temparray[3]);
		Unicode::snprintf(RX_TextAreaBuffer, RX_TEXTAREA_SIZE, Datarray);
	}
	else if(UARTToggleButton.getState()==0) //UART 3
	{
		Unicode::strncpy(RX_TextAreaBuffer, (char*)RX3_String_cpy, RX_TEXTAREA_SIZE);
	}
	RX_TextArea.invalidate();
}

The HAL_UART_Receive_DMA function from main is definitely working as I can see the signal on oscilloscope.

What is the workaround to show the string received straight to view?

MM..1
Chief III
June 29, 2023

You dont read my text carefuly, you need check if new str received. Most simple method is after show string erase cpy, and on callback fill cpy string. 

Then in some right place if (cpy[0] != 0) call your show func with erase on end ... Right place is for example tick handler created in screen.

Krautermann
Senior
June 29, 2023

No offense to you but to be honest it's kinda hard to understand what you are trying to say with the way you write your English :(

I read your response multiple times to try to understand your suggestion. The Transmit now works, I have put the HAL_UART_Transmit in main file and can see it displayed on view. But for receive, if I remove it from modelListener, it does not work.