cancel
Showing results for 
Search instead for 
Did you mean: 

Why we need C++ for modern hardware

vybor
Associate III

Modern microcontrollers have a lot of perifhery. Several buses of different types.

STM32 hardware has outgrown C. Too much complex perifhery to manage with procedural language.

ST software is much behind of ST hardware.

 

Look at any I2C or SPI open source C library. Any can be used with one device of some type only.

In case of I2C there are lines like this in header:

#define SSD1306_I2C_PORT hi2c1

#define SSD1306_I2C_ADDR (0x3C << 1)

and

extern I2C_HandleTypeDef SSD1306_I2C_PORT;

in C file.

If somebody need one device on differnt port or on different device address he have to edit source files of library.

If somebody need more devices of the same type on different device addresses and/or on different ports, he have to throw away library and write own solution.

It is not possible to get library and make something like this:

i2c_device1 = create_i2c_device(port1, dev_adr1, params1...);

i2c_device2 = create_i2c_device(port1, dev_adr2, params2...);

i2c_device3 = create_i2c_device(port2, dev_adr3, params3...);

 

It's impossible to use two OLED i2c displyas with open source C libraries. It's inacceptable.

I convert C library to C++ and can use

  ssd1306cpp oled1
    { &hi2c1, dev1_adr, disp1_buf, disp1_w, disp1_h, buf1_sz };

  ssd1306cpp oled2
    { &hi2c2, dev2_adr, disp2_buf, disp2_w, disp2_h, buf2_sz };

We definitly need C++ to manage great ST hardware.

 

10 REPLIES 10
TDK
Super User

Related/duplicate:

Generation code to CPP files - STMicroelectronics Community

 

> It's impossible to use two OLED i2c displyas with open source C libraries.

Huh? I do that. It's working okay for me.

If you feel a post has answered your question, please click "Accept as Solution".
Andrew Neil
Super User

LOL!

You've been ranting on about how "terrible" CubeMX-generated initialisation code is because it creates loads of structs with runtime initialisations.

So how, exactly, do you think stuff like this is achieved by C++ ?!

 


@vybor wrote:
 

It is not possible to get library and make something like this:

i2c_device1 = create_i2c_device(port1, dev_adr1, params1...);

i2c_device2 = create_i2c_device(port1, dev_adr2, params2...);

i2c_device3 = create_i2c_device(port2, dev_adr3, params3...);

Of course it's possible !

C++ has some features to make it more convenient, but it's certainly possible to do it in C.

If a particular library doesn't allow it, that's a limitation of the library - nothing to do with the fact that it's written in C.

 


@vybor wrote:

In case of I2C there are lines like this in header:

#define SSD1306_I2C_PORT hi2c1

#define SSD1306_I2C_ADDR (0x3C << 1)

Those things should never be part of the library - they would be part of the user's code.

Those would be the parameters that would be passed to your create_i2c_device() function in the user's instanciation(s).

Again, that's a limitation of the library - not a limitation of C.

A complex system that works is invariably found to have evolved from a simple system that worked.
A complex system designed from scratch never works and cannot be patched up to make it work.

I partially agree.

In C you can write object oriented code. Just not with the same syntax, compile checks and runtime features as C++. In the past I have written C++ wrappers for HAL drivers. So you can combine both C and C++.

Modern C++ adds features that are more useful than objects imho. Such as templates, constexpr etc.
This let's you can let the compiler do compile time checks and calculations. It also significantly reduces reliance on macros. Namespaces also help make names shorter.
But for my applications 90% of my code is functional.

The generated code of ST has some shortcomings:

  • lack of user context in callback functions, means you need to create your own mapping logic: https://community.st.com/t5/stm32-mcus-embedded-software/user-defined-context-in-hal-callbacks/m-p/783093
  • only 1 configuration instead of multiple, makes board version dependent code harder to write
  • no option to dynamically configure hardware runtime, init functions are generated and optmized, but if you want more flexibility you need to rewrite the code. For instance deinitializing a GPIO pin could also deinit the gpio clock if that clock is no longer used for any pin to save power. If you want this behavior you need to write it yourself.

 

 

 

 

Kudo posts if you have the same problem and kudo replies if the solution works.
Click "Accept as Solution" if a reply solved your problem. If no solution was posted please answer with your own.

@unsigned_char_array wrote:

The generated code of ST has some shortcomings:


Indeed. But these have nothing to do with being written in C rather than C++

 


@unsigned_char_array wrote:

Modern C++ adds features that are more useful than objects imho.


Indeed - no argument that C++ has benefits.

But for @vybor to say that it's essential is just not true.

A complex system that works is invariably found to have evolved from a simple system that worked.
A complex system designed from scratch never works and cannot be patched up to make it work.

If one needs several divices of one type he must to reimplement C++ functionality with restricted C compiler.

1 Make struct to hold state of each device

2 Change function signatures to pass the structure along the call chain. All i2c oled libraries I can found, can work with one device from the box.

Not more efficiet than C++ solution. In embedded software no need to use hierachy and virtual function, so virtual destructor is not needed. C++ class and C structure consume the same resources. C++ solution don't require to change API, this pointer is passed under the hood.

Shortcomings are

1. No consexpr and consteval to make as much as possible at compile time

2. No namesaces and headache with ugly prefixes to make function name unique

3. no templates

4. no RAII

5. No bit_cast

6. No incapsulation, all not static function go to global scope

7 Impossible to hide and protect data members

8 no stl, some functionallity is very convenient for embedded.

9. C++ much more stronger and catch errors wich pass through C compiler

I don't understand why ST refuse to use modern C++.


@vybor wrote:

All i2c oled libraries I can found, can work with one device from the box..


Again, that's a limitation of those libraries - not the fact that they're written in C.

Have you moaned to all those library authors to tell them to re-write?

 


@vybor wrote:

I don't understand why ST refuse to use modern C++.


They don't refuse - TouchGFX uses C++, AFAIK.

There is support for it; I guess the demand just isn't there.

A complex system that works is invariably found to have evolved from a simple system that worked.
A complex system designed from scratch never works and cannot be patched up to make it work.
TDK
Super User

It's fine to have preferences. I prefer C++ as well. But it's another thing to come into an established architecture and system and want the world to change for your desires. Unless you have considerable resources, you don't get to do that, you only get to use what is available.

Is namespace::function better than namespace_function? What makes one uglier than the other?

> If one needs several divices of one type he must to reimplement C++ functionality with restricted C compiler.

Again, this is simply not true. A long time ago there was (and still is) https://stm32f4-discovery.net/about/ which managed to work with multiple peripherals, all using C code. All before HAL and the Cube microsystem. Not to mention HAL is obviously set up to work with multiple peripherals at once.

IRQ handlers get called with no context. Any OOP solution still needs to manage that using plain C. Apart from that, most things are amenable to a C++ implementation.

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

@vybor wrote:

If one needs several divices of one type he must to reimplement C++ functionality with restricted C compiler.

Linux is written in C, not C++ and handles multiple instances of a device just fine. So it can be done.

 


@vybor wrote:

2 Change function signatures to pass the structure along the call chain.


The problem is, like I wrote, the lack of a user context pointer in the handle structs.

 


@vybor wrote:

All i2c oled libraries I can found, can work with one device from the box.

Many libraries are written for 1 instance only. Adding the ability to use more than 1 instance can often be done without overhead. The solution is to modify the library to add this ability. If it does add overhead you can make it optional behavior using conditional compilation. Make a pull request so others can benefit too.

 


@vybor wrote:

4. no RAII


I've never needed RAII in embedded code. I have used it once for SPI slave select/deselect in combination with a mutex to create a SPI session object. But generally you allocate things only once in embedded systems.

 


@vybor wrote:

1. No consexpr and consteval to make as much as possible at compile time

2. No namesaces and headache with ugly prefixes to make function name unique

3. no templates


Again you can add your own C++ code. No problem. I use TouchGFX which is written in C++. It works alongside of C without issue. And you can wrap the HAL or LL library with C++.

 


@vybor wrote:

6. No incapsulation, all not static function go to global scope

7 Impossible to hide and protect data members


Simply not true. You can use function pointers and private struct definitions.

 

Kudo posts if you have the same problem and kudo replies if the solution works.
Click "Accept as Solution" if a reply solved your problem. If no solution was posted please answer with your own.
vybor
Associate III

But these have nothing to do with being written in assembler rather than C