Software drivers for the mcu peripherals in C++
Avoid the placement new
The placement new you are doing looks redundant. PeripheralRegs is a POD type, so its member values will probably not be initialized, but to avoid any doubt I would just write:
Peripheral::Peripheral(const PeripheralCfg&amp; peripheral_cfg, uint32_t base_address):
    regs{reinterpret_cast&lt;PeripheralRegs*&gt;(base_address)}
{
    regs-&gt;control_reg.cfg_bit_01 = static_cast&lt;uint32_t&gt;(peripheral_cfg.cfg_bit_1);
    regs-&gt;control_reg.cfg_bit_02 = static_cast&lt;uint32_t&gt;(peripheral_cfg.cfg_bit_2);
    regs-&gt;control_reg.cfg_bit_03 = static_cast&lt;uint32_t&gt;(peripheral_cfg.cfg_bit_3);
}

Toggle using XOR
You can rewrite toggleReset() by using the XOR operation:
void Peripheral::toggleReset()
{
    regs-&gt;control_reg.reset_bit ^= 1;
}

Why the k prefix for enum class values?
I see the values of enum class FunctionUsage are prefixed with a k. This looks like Hungarian notation, but I don't see Hungarian notation used anywhere else in this code. I suggest you drop it. Since it's an enum class, there is no chance that these values would conflict with anything else.
Use arrays where appropriate
I see several variables being repeated with just a different number at the end. Those are often a candidate to be replaced by arrays. Consider writing:
struct PeripheralCfg
{
  FunctionUsage cfg_bits[3];
};

...

struct DriversCfg 
{
    PeripheralCfg periph_cfgs[2] = {
        {FunctionUsage::kAdcNotUsed, FunctionUsage::kAdcUsed, FunctionUsage::kAdcUsed},
        {FunctionUsage::kAdcNotUsed, FunctionUsage::kAdcNotUsed, FunctionUsage::kAdcUsed},
    };
};

...

class Hal {
    ...
    Peripheral *peripherals[2];
    ...
};

And so on. You can always rename the variables you used before to refer to an array element, for example periph_01 becomes periph[0]. Also, it opens up possibilities to use for-loops to avoid repetition:
for (auto &amp;periph: hal.peripherals)
    periph-&gt;enable();

Although it looks silly now with an array of only two elements, it will quickly become more useful if you have to support hardware which supports more peripherals.
Make Hal::configuration static const
It looks like Hal::configuration is only meant to be read once, and never changed. You should change it into a static const variable:
class Hal {
    ...
    static const DriversCfg configuration;
    ...
};

Although it does look a bit weird this way. If it's only used by the constructor of Hal, then this should not be a (static) class member at all. You could move it completely into Hal.cpp:
static const struct
{
    PerpheralCfg periph_configs[2] = {...};
} configuration;

Hal::Hal() {
    perhiperal[0] = new Peripheral(configuration.periph_cfgs[0], PERIPH_01_BASE_ADDRESS);
    perhiperal[1] = new Peripheral(configuration.periph_cfgs[1], PERIPH_02_BASE_ADDRESS);
}

You could also keep the configuration in DriversCfg.h, but then still exactly as I've shown here.
As for the order of instantiation: global variables are instantiated before main() runs, so configuration will be valid before the variable hal is constructed. If it was still a regular member variable, then it would also have been instantiated before the body of the constructor was run, so your code is fine in that respect.
Avoid unnecessary memory allocations
Why does Hal need to allocate the Peripherals on the heap? Especially on an MCU you want to avoid dynamic memory allocations. So instead of having pointers to Peripherals inside class Hal, just have them by value:
class Hal {
public:
    Peripheral peripherals[2];
    Hal();
};

...

Hal::Hal():
    peripherals{
        {configuration.periph_cfgs[0], PERIPH_01_BASE_ADDRESS},
        {configuration.periph_cfgs[1], PERIPH_02_BASE_ADDRESS},
    }
{}

And then use it like so:
int main(...)
{
    Hal hal;
    for (auto &amp;periph: hal.peripherals)
        periph.enable();
}