vendredi 1 février 2019

What is the modern C++ way of having a constexpr const pointer to a volatile memory location for embedded applications?

In building libraries for controlling hardware on embedded microprocessors, a common task is manipulating bits at specific memory locations for controlling hardware features.

In AVR processors, Atmel (now Microchip) provides macros that expand to something like this:

#define PORTA (*(volatile uint8_t *)(0x25))

Which enables things like:

PORTA |= 1;

Now in C++11 (and newer), it is desirable to replace almost any usage of #define with constexpr.

In older versions of the GCC C++ compiler (4.9.2), the following compiled:

#include <avr/io.h>
constexpr volatile uint8_t *const PortA = &PORTA;

In version 8.2.0, the above does not compile and gives errors:

error: reinterpret_cast from integer to pointer

I'm not looking for explanations of why you cannot use reinterpret_cast inside a constexpr context or why integer to pointer conversion is illegal.

What is the correct way to have a constexpr pointer to volatile memory in modern C++?

I've seen suggestions of storing the memory address of PORTA in a constexpr uintptr_t and then reinterprect_casting that to volatile uint8_t * const at runtime for bit manipulation.

For instance, this works and even compiles to a single sbi instruction in avr-gcc as expected.

#include <stdint.h>
constexpr uintptr_t PortA = 0x25;
void set() { *((volatile uint8_t *)(PortA)) |= 1; }

However it takes a decent amount of ugly boilerplate to use Foo as the pointer it is intended to be.

This also has the problem that it seem to be impossible to use the PORTA macro directly. We're instead forced to hard-code the memory address 0x25 which breaks certain desirable portability features.

It feels like I'm missing something obvious buy my searches have not yielded anything fruitful.

For instance, this feels like an "address constant expression", but that seems to relate to referring to statically allocated const values like which is not quite what I want.

const char str[] = "FooBar";
constexpr const char * x = str + 2;

Aucun commentaire:

Enregistrer un commentaire