2019 12 03 Cafe CPP Mcu
2019 12 03 Cafe CPP Mcu
Cores 1 to N 1 to N
MMU NO YES
Memory Management Unit ?
Memory Management Unit ?
●
No MMU → no Process (mostly)
●
No MMU → heap memory fragmentation
●
No MMU → no Segfaults
●
No MMU → different operating systems
Programming models
●
Operating system
– Good for complex multiprogramming problems
●
Bare metal
– Faster and simpler for basic control loops
So what does it looks like?
Let’s dive into a datasheet
Let’s consider a simple example
●
LED blink, AKA the MCU hello world
●
With C and C++
●
C++ shouldn’t produce more assembly than C
●
Should be more expressive and safer
●
There shouldn’t be anything done a run time that
can be done at compile time
Raw C version
int main(void)
{
// enable GPIOB
*((volatile uint32_t*)(0x40023830)) |= (1 << 1);
// configure GPIO PB8 as output
*((volatile uint32_t*)(0x40020400)) |= (1 << 16);
for (;;)
{
//toggle led
*((volatile uint32_t*)(0x40020414)) = *((volatile uint32_t*)(0x40020414)) xor (1 << 8);
for (volatile int i = 0; i < 1024 * 1024 * 2; i++);
}
}
C++ Version
int main(void)
{
rcc::enable_clock(stm32f7, stm32f7.GPIOB);
set_direction(stm32f7, GPIOB8, stm32::gpio::mode::output);
for (;;)
{
stm32f7.GPIOB.od.get<8>() = !stm32f7.GPIOB.od.get<8>();
for (volatile int i = 0; i < 1024 * 1024 * 2; i++)
;
}
}
Overhead?
Can we make this more interesting?
Can we make this more interesting?
●
Let’s make a software PWM led blink
●
We want to decouple how we set LED value
from PWM code
●
We want to decouple how we compute duty
cycle from PWM code
Strong types
Let’s step back a little
●
We’ll have to deal a lot with peripherals and registers
●
Registers have many bit fields
●
Registers or bit fields can be read-only
●
Embedded systems are deterministic (no hot-plug..)
●
Debug and Tests are easier on desktop PC
●
Prefer enum classes to literals
Registers
●
Not convenient with spaced registers
●
Bit field access not much better
●
User has to “hack” memory layout of structures
●
User has to ensure that structure is packed
Registers (simplified)
template <typename T, const uint32_t address>
struct reg_t
{
inline reg_t& operator=(const T& value) noexcept
{
*reinterpret_cast<T*>(address) = value;
return *this;
}
constexpr operator T&() noexcept { return *reinterpret_cast<T*>(address); }
constexpr operator const T&() const noexcept { return *reinterpret_cast<T*>(address); }
};
MP3
MCU Codec
Now let’s make a basic MP3 Player
●
No filesystem
●
Simple infinite loop
●
Made with modern C++
●
Strong decoupling between layers
●
Use SD bus but should work with SPI
Basic MP3 player
●
Clocks, IO, peripheral init
●
SD card init
●
MP3 codec init
●
Main loop
– Get next data block
– Give data block to codec
Let’s look the code
Simple MP3 player
●
Main loop can easily work on any system
●
SD card SW protocol decoupled from HW layer
●
Source code looks simple and expressive
●
Almost no SW error possible
●
We can easily develop/test a filesystem driver on
computer
Conclusions
●
Writing no-overhead C++ on MCU is possible
●
Const const const!!!
●
C++ allow modular code with no run-time costs
●
C++ can be safer than C
●
C++ doesn’t help to solve HW bugs/issues
●
C++ isn’t “C with classes”
●
C++ templates are “Pay for what you use”
●
Templates debug is a big pain
●
Computers have std::, microcontrollers’ll have mst::