cancel
Showing results for 
Search instead for 
Did you mean: 

How to add GPIO bindings to my VS Application?

HTD
Senior III

I made a test project for my discovery board with TouchGFX.

I needed the UI to react for a pin state change.

I've seen tutorials, where a GPIO accessing function was added to the `main.c` file. Then it could be added as `extern "C"` from `Model.cpp` file.

It looks awful! The main.c file is huge and full of generated stuff, even finding my function there is challenging.

So what I'm looking for is a way to just put my additional code into a separate header file.

The problem is the STM32CubeIDE project doesn't even have headers directory.

Another weird thing is VS showing a warning about my externed function, because it doesn't have the file it was defined in its `Application` project. However, when the code is compiled for the device, the symbol can be linked and my test application works.

What is the proper and normal way of calling `HAL_GPIO_ReadPin()` from my VS project?

The only way I found is to add the function that does it to the `main.c` from STM32CubeIDE project level, then extern it in `Model.cpp`.

What I need is a kind of bridge / binding file that from the one end can access all symbols `main.c` can access, and on the other end it is visible and usable for `Model.cpp`.

BTW, is there a way to stop VS from complaining about undefined function in `Model.cpp`? The function is defined in `main.c`. But I can't put `main.c` in my VS project, can I?

I'm thinking of making a class or a namespace that contains HAL accessing functions, but the problem is, that the other side of it is not in the VS project, it is in STM32CubeIDE project, and even there - I can't create a header file.

I'm also thinking about ugly workaround with creating the header file in the same directory as main.c and then include it in main.c. That should work, but that's an ugly hack.

5 REPLIES 5
TDK
Guru

> The problem is the STM32CubeIDE project doesn't even have headers directory.

There is Core/Inc. You can also make your own.

> What is the proper and normal way of calling `HAL_GPIO_ReadPin()` from my VS project?

Include the HAL library headers, starting with "stm32h7xx_hal.h" or similar, and call it as you would call any other function.

If you feel a post has answered your question, please click "Accept as Solution".
HTD
Senior III

I don't see Core/Inc in the project. There is `includes` branch that contains it, but it's not a normal project folder when I can add files.

Then, I do can include the HAL headers in my own `.h` file I added to the STM32CubeIDE project, it works, however, I absolutely cannot include those headers in VS, those headers require complex project configuration not present in the VS project.

That creates another problem: how can I pass a pointer to `GPIO_TypeDef` from my C++ code in VS project? I guess I can't, because that project doesn't contain HAL headers and I couldn't add them because of configuration issues.

My current workaround is to just make functions, that doesn't require `GPIO_TypeDef` type defined, I can hardcode the correct reference in my functions. I can pass simple types with no problem with extern.

I also found a workaround for VS error:

#ifndef SIMULATOR
extern "C" bool f(uint16_t x);
#else
bool f(uint16_t x) { return true; }
#endif

So the simulator app doesn't see the extern at all, but when the code is compiled for the device it works. Also, assuming the `f` returns the `x` pin state, it can return predefined state for the simulator.

TDK
Guru

There is no way you can work with or pass objects of type GPIO_TypeDef if the compiler doesn't have a definition for what that is.

Visual Studio is a fully featured IDE probably eclipsing STM32CubeIDE in features and certainly eclipsing it in longevity, support, and total userbase. There is absolutely no technical limitation preventing you from including HAL files in the project structure. Or does VS mean something else here?

If you feel a post has answered your question, please click "Accept as Solution".
HTD
Senior III

The problem is I don't know how to do it. I added include directories to the VS project file. Then I added the headers. Then VS showed about 1000 errors. One of them was like `CORE_CM7` not defined, obviously. I know it's defined somewhere in the STM32CubeIDE project, but that's just a tip of an iceberg, there are hundreds of similar issues and solving them one by one would take longer than writing the entire application.

BTW, even when I included HAL in my Cube project, it didn't see HAL_GPIO functions, when I included `main.h` it worked. It's weird, because I tracked what `main.h` includes and there's not much else there except HAL. I copied all includes from `main.h` to my new file `bridge.h` - it didn't work. When I replaced those includes with `#include "main.h"` it worked. I don't understand why.

Considering what I've found in all tutorial videos... It's all just putting ALL the GPIO functions in `main.c`. That's simple, but super messy and ugly. Moving all that code to a new file or two is way better, but still... I just wonder if there is a simpler and cleaner way of doing this.

What I want to achieve is a quick replicable process of adding HAL related function to my Model.

HTD
Senior III

Here's my workaround:

bridge.h:

#ifndef APPLICATION_USER_CORE_BRIDGE_H_
#define APPLICATION_USER_CORE_BRIDGE_H_
 
#include "main.h"
#include "stdbool.h"
 
#ifdef __cplusplus
extern "C" {
#endif
 
bool GetPinState() { return HAL_GPIO_ReadPin(TEST_PIN_GPIO_Port, TEST_PIN_Pin) == GPIO_PIN_SET; }
 
#ifdef __cplusplus
}
#endif
 
#endif /* APPLICATION_USER_CORE_BRIDGE_H_ */

main.c:

/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "cmsis_os.h"
#include "app_touchgfx.h"
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "bridge.h"
/* USER CODE END Includes */

Model.cpp:

#include <gui/model/Model.hpp>
#include <gui/model/ModelListener.hpp>
 
#ifndef SIMULATOR
extern "C" bool GetPinState();
#else
bool GetPinState() { return true; }
#endif // !SIMULATOR

Now, adding more HAL code requires putting it both in bridge.h and Model.cpp. As clean as it gets.

I was able to add "../../../CM7/Core/Inc" as "Core Includes" linked folder. Then I was able to add "bridge.h" there. The code snippets contain only top fragment of the files containing the relevant code.

Since my model doesn't need to access ALL GPIO ports and HAL features, it's probably fine it's all defined in the bridge.h file. Now my model takes only what it needs, also defines behavior for the simulator.

Doing this from scratch is simple, create linked folder, add "bridge.h" header there, add include in "main.c", add extern in "Model.cpp" or "Model.hpp", done.

Additional benefit - when coding the bridge AND Model from STM32CubeIDE I have access to my defined pin names, all IDE logic works as intended, pressing F3 takes me to definitions and Ctrl+B builds the project exactly as TouchGFX does.

Then I can work on UI and interaction in Visual Studio.

IDK, if anyone has better idea, please share.