cancel
Showing results for 
Search instead for 
Did you mean: 

STM32CubeIDE and C++ support

mattias norlander
ST Employee
Hi C++ Developers,
 
As you may know, developers downliading Cube tools from st.com will receive an e-mail asking them to provide feedback. From this feedback we see some complaints vs the C++ support in STM32CubeIDE. The complaints are however lacking details. We are aware of several C++ topics which could be improved. But without detail, it is hard to tell what is seen as the highest priority... Here is where we need your help!
 
Brainstorming on the main C++ issues in STM32CubeIDE (and Cube ecosystem) I arrive at this list of issues::
 

 

What is your main concern related to C++ support in CubeIDE? You may have issues not even listed... Please share your opinions!
 
Kind regards, Mattias
 
12 REPLIES 12

@bbee wrote:

To be able to build a correct C++ Wrapper around the HAL C-Funktions you should extend the Handle-Typedefs with some sort of User Data Pointer 


Exactly. Like I wrote in my comment above. It was declined for HAL V1. But it is present in HAL V2 as an opion (can be enabled with a define).

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.

Every plain pointer stored in writable memory is a vulnerability in small embedded systems. So these additional "context" pointers, while convenient for some developers or for rapid prototyping, aren't 100% good thing. 

(let alone the ugly typecasts, sugared by c++ reinterpret_cast gimmicks)

In the context of the given example - usually a handler is shared by only a small number of instances. For more robustness, it can be coded like this:

extern "C" void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart)
{
  switch(huart){
    case &huart1:
      gBspUart1->OnTxComplete();
      break;
    case &huart4:
      gBspUart4->OnTxComplete();
      break;
    default: // no more known UARTs
      Error_Handler();
   }
}

It exposes more stuff as globals, but the addresses are constant (resolved by linker in build time)


@Pavel A. wrote:

Every plain pointer stored in writable memory is a vulnerability in small embedded systems. So these additional "context" pointers, while convenient for some developers or for rapid prototyping, aren't 100% good thing. 


You are right in case of safety critical systems. But the HAL uses pointers everywhere. Once you need to take potential data corruption of pointers very serious nothing of the HAL is safe. There are ways to add some redundancy to context pointers.

You can do some checks on a pointer value in a callback function before it's used. Such as checking if the pointer is not NULL, is in RAM region, and is aligned properly for object type. Still no guarantee the pointer is pointing to the correct instance or even the correct type.
You can additionally do some sanity checks on the dereferenced object such as checking if values of the object make sense.
Another option is add a reference to the handle/peripheral to the object. So that you can check in the callback function if the context referenced by the handle also refers back to the handle. Like a doubly linked list. Small chance a random block of memory contains that specific address.

If you really want to avoid using pointers you also use the void* of the context pointer as a 32 bit data type. You could squeeze in an enum, and a CRC if you are really paranoid. Then you check for valid enum range and check CRC and use a switch statement to select your file scope object.

Ultimately embedded software should do some checks to ensure everything is running correctly. Brownout and watchdog are helpful. But not sufficient. Memory can get corrupted by cosmic radiation, firmware bugs, silicon bugs, incorrect DMA configuration, etc.

 


@Pavel A. wrote:

(let alone the ugly typecasts, sugared by c++ reinterpret_cast gimmicks)


Nothing wrong this those. It's clear what the intention is. If you want to avoid casting we need to make the pointer type of the user context also configurable with a define per peripheral. That seems like a sane option.

 

EDIT: (this was posted after I clicked reply)


@Pavel A. wrote:

In the context of the given example - usually a handler is shared by only a small number of instances. For more robustness, it can be coded like this:
It exposes more stuff as globals, but the addresses are constant (resolved by linker in build time)


This doesn't work. You cannot put addresses of objects in a case value. I tried. You have to use enums instead.

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.