cancel
Showing results for 
Search instead for 
Did you mean: 

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

Krautermann
Senior II

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. 
 

1 ACCEPTED SOLUTION

Accepted Solutions
MM..1
Chief III

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 .

 

View solution in original post

13 REPLIES 13
redmig
Associate III

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!

 

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?

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..

These strings: extern uint8_t RX1_String_cpy[512] are for the HAL_UART_Receive which are found in the main.c file. They are being exported to model so that the received strings can be displayed on the LCD.

What I want is the reverse direction (send data from UI to main WITHOUT RTOS). I want to get the string entered from the user on the LCD and send it from model to main. That's my problem right now. 

 I already have the code working for the view.cpp file. And it is getting sent to presenter and then the presenter is sending it to model. But I don't know how to get the model to send the string to main.c file. 

void Screen2View::SendClicked()
{
	if(UARTToggleButton.getState()==0)
	{
		UART = 0;
		if(DMAToggleButton.getState()==0)
		{
			DMA = 0;
		}
		else
		{
			DMA = 1;
		}
	}
	else if(UARTToggleButton.getState()==1)
	{
		UART = 1;
		if(DMAToggleButton.getState()==0)
		{
			DMA = 0;
		}
		else
		{
			DMA = 1;
		}
	}
	presenter->SendData2MCU(UART, DMA, DataBuffer);

	memset(TX_Buffer, '\0', TX_TEXTAREA_SIZE);
}
void Screen2Presenter::SendData2MCU(int UART, int DMA, uint8_t* data)
{
	model->SendData2MCU(UART, DMA, data);
}

Now in the model.cpp file, what can I write to send the function SendData2MCU(UART, DMA, DataBuffer) to main.c?

redmig
Associate III

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?

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
Chief III

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 .

 

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?

I have removed the function (modelListener->RX1_3Data((char*) RX1_String_cpy, (char*) RX3_String_cpy);) from model::tick() as you suggested as well as from presenter.
And then I extern the RX_String to view directly:

#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 do not see the string being displayed on LCD anymore. I only see it when I put the function in modelListener. Is there a workaround? Or what am I doing wrong? 
The HAL_UART_Receive is definitely working from my main as I can see signal on the oscilloscope.

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));
	}
}