Embedded Systems için C++ Temelleri
Bir Formula 1 aracının elektronik kontrol ünitesini (ECU) düşün. Saniyede binlerce kez sensör verisi okuyor, motor enjeksiyonunu ayarlıyor, fren basıncını hesaplıyor. Bellek 512 KB, işlemci 200 MHz, hata toleransı sıfır. Bu sistemde new ile bellek ayıramazsın — heap fragmentation olur ve 50. turda araç durur. Exception fırlatamazsın — stack unwinding milisaniyelerce sürer ve fren tepki süresini kaçırırsın. Ama C++ kullanabilirsin. Template'ler, RAII, constexpr, güçlü tip sistemi — hepsi zero-cost. Derleyici bunları derleme zamanında çözer, runtime'da tek bir ekstra bayt veya CPU cycle'ı harcamazlar.
Embedded C++ demek "C++'ın bir alt kümesi" demek. Bazı özellikleri kullanmazsın ama kullandıkların sana C'nin asla veremeyeceği güvenlik ve soyutlama gücü sağlar.
Embedded Nedir, Nerede Kullanılır?
Embedded system (gömülü sistem), belirli bir görevi yerine getirmek üzere tasarlanmış, genellikle kısıtlı kaynaklara sahip bilgisayar sistemidir. Masaüstü bilgisayarın aksine, kullanıcı farklı programlar çalıştırmaz — sistem tek bir iş yapar ve onu çok iyi yapar.
Kullanım Alanları
| Alan | Örnekler | Kısıtlamalar |
|---|---|---|
| Otomotiv | Motor ECU, ABS, airbag | Gerçek zamanlı, güvenlik kritik |
| Tıbbi Cihaz | Kalp pili, MR cihazı, insülin pompası | FDA onaylı, hata toleransı sıfır |
| IoT | Akıllı termostat, sensör ağları | Düşük güç, sınırlı bellek |
| Havacılık | Uçuş kontrol, autopilot | DO-178C sertifikasyonu |
| Tüketici Elektroniği | Çamaşır makinesi, TV kumandası | Düşük maliyet, düşük güç |
| Endüstriyel | PLC, robot kontrolü | 7/24 çalışma, güvenilirlik |
Tipik Kaynak Kısıtlamaları
RAM: 1 KB – 512 KB (mikrodenetleyici) veya 32 MB – 512 MB (uygulama işlemci)
Flash/ROM: 16 KB – 2 MB (program depolama)
CPU: 8 MHz – 400 MHz (mikrodenetleyici) veya 1+ GHz (uygulama işlemci)
Güç: Pil ile çalışan sistemlerde miliwatt düzeyinde bütçe
C++ vs C: Embedded'da Neden C++?
Embedded dünyası geleneksel olarak C'nin kalesidir. Ama modern C++ (C++11 ve sonrası) zero-cost abstractions felsefesiyle embedded'a güçlü bir alternatif sunar.
Zero-Cost Abstractions Ne Demek?
"Kullanmadığın şey için ödeme yapmazsın, kullandığın şey için elle yazabileceğinden daha fazla ödemezsin." — Bjarne Stroustrup
// C versiyonu: LED kontrolü
// led_controller.c
typedef enum { LED_RED = 0, LED_GREEN = 1, LED_BLUE = 2 } LedColor;
void led_set(LedColor color, int brightness) {
// Hatalı kullanım: led_set(42, 255) — derlenir, çalışır, yanlış yapar
volatile uint32_t* led_reg = (volatile uint32_t*)0x40020014;
*led_reg = ((uint32_t)color << 8) | (uint32_t)brightness;
}// C++ versiyonu: LED kontrolü
// led_controller.cpp
#include <cstdint>
enum class LedColor : uint8_t { Red = 0, Green = 1, Blue = 2 };
class LedController {
public:
static void set(LedColor color, uint8_t brightness) {
// led_set(42, 255) → DERLEME HATASI (enum class güvenliği)
auto reg = reinterpret_cast<volatile uint32_t*>(LED_BASE + LED_DATA_OFFSET);
*reg = (static_cast<uint32_t>(color) << 8) | brightness;
}
private:
static constexpr uintptr_t LED_BASE = 0x40020000;
static constexpr uintptr_t LED_DATA_OFFSET = 0x14;
};
// Kullanım
// LedController::set(LedColor::Red, 128);
// LedController::set(42, 128); // DERLEME HATASI!Her iki versiyonun ürettiği assembly aynıdır. Fark sıfır. Ama C++ versiyonu tip güvenliği, isim alanı izolasyonu ve derleme zamanı doğrulama sağlıyor.
C++ Avantajları
| Özellik | C | C++ | Maliyet |
|---|---|---|---|
| Tip güvenliği | Zayıf (implicit cast) | Güçlü (enum class, templates) | Sıfır |
| RAII | Yok (free'yi unutabilirsin) | Otomatik kaynak yönetimi | Sıfır |
| Templates | Yok (macro ile taklit) | Tip güvenli generics | Sıfır (compile-time) |
| constexpr | Yok (#define ile sabit) | Derleme zamanı hesaplama | Sıfır |
| Namespace | Yok (prefix: my_lib_func) | İsim alanı izolasyonu | Sıfır |
| Inline fonksiyon | C99'da var ama sınırlı | Tam destek | Sıfır |
Kısıtlamalar: Ne Kullanılmaz?
Embedded C++'ta bazı özellikler ya yasaklanır ya da çok dikkatli kullanılır. Sebebi: runtime maliyeti tahmin edilemez veya kaynak tüketimi kontrol edilemez.
1. No Exceptions
Exception handling, stack unwinding mekanizması gerektirir. Bu mekanizma:
Her fonksiyon çağrısı için exception tablo bilgisi tutar (ROM tüketimi)
Exception fırlatıldığında stack'i geri sararken belirsiz süre harcar
Gerçek zamanlı sistemlerde deadline miss riskidir
// ❌ Embedded'da KULLANMA
int parse_sensor(const char* data) {
try {
int value = convert(data);
if (value < 0) throw std::runtime_error("Negatif değer");
return value;
} catch (const std::exception& e) {
log_error(e.what());
return -1;
}
}
// ✅ Embedded'da KULLAN: Hata kodu döndür
enum class SensorError : uint8_t {
Ok = 0,
InvalidData = 1,
OutOfRange = 2,
Timeout = 3
};
struct SensorResult {
int32_t value;
SensorError error;
bool ok() const { return error == SensorError::Ok; }
};
SensorResult parse_sensor(const char* data) {
int32_t value = convert(data);
if (value < 0) {
return {0, SensorError::OutOfRange};
}
return {value, SensorError::Ok};
}2. No RTTI (Runtime Type Information)
dynamic_cast ve typeid, her polymorphic sınıf için runtime tip bilgisi tablosu tutar. Bu ek ROM ve RAM tüketir.
// ❌ Embedded'da KULLANMA
void process(Shape* shape) {
if (auto* circle = dynamic_cast<Circle*>(shape)) {
handle_circle(circle);
}
}
// ✅ Enum tabanlı tip kontrolü
enum class ShapeType : uint8_t { Circle, Rectangle, Triangle };
class Shape {
public:
virtual ShapeType type() const = 0;
virtual int32_t area() const = 0;
virtual ~Shape() = default;
};
void process(Shape* shape) {
switch (shape->type()) {
case ShapeType::Circle:
handle_circle(static_cast<Circle*>(shape));
break;
case ShapeType::Rectangle:
handle_rectangle(static_cast<Rectangle*>(shape));
break;
default:
break;
}
}3. No Dynamic Allocation (veya Çok Dikkatli)
new ve delete (heap allocation):
Heap fragmentation: Uzun süre çalışan sistemlerde bellek "delik deşik" olur
Allocation failure:
malloc()nullptrdönebilir — embedded'da "daha sonra deneyelim" lüksü yokBelirsiz süre: Allocator'ın ne kadar sürede döneceği garanti değil
// ❌ Embedded'da KULLANMA
void handle_message() {
auto* buffer = new uint8_t[1024]; // Heap allocation — tehlikeli!
// ... kullan ...
delete[] buffer; // Unutursan → memory leak → 3 gün sonra RAM biter
}
// ✅ Stack allocation
void handle_message() {
uint8_t buffer[1024]; // Stack'te — otomatik temizlenir, hızlı
// ... kullan ...
} // Otomatik temizlenir
// ✅ Static allocation (global pool)
class MessagePool {
public:
struct Message {
uint8_t data[256];
uint16_t length;
bool in_use;
};
Message* acquire() {
for (auto& msg : pool_) {
if (!msg.in_use) {
msg.in_use = true;
return &msg;
}
}
return nullptr; // Pool dolu — hata kodu ile ele al
}
void release(Message* msg) {
if (msg) msg->in_use = false;
}
private:
Message pool_[32]; // Derleme zamanında sabit boyut, static bellek
};Compiler Flag'leri
# Exception'ları devre dışı bırak
g++ -fno-exceptions -fno-rtti -Os -o firmware main.cpp
# Tipik embedded compiler flag'leri (ARM Cortex-M)
arm-none-eabi-g++ \
-mcpu=cortex-m4 \ # Hedef işlemci
-mthumb \ # Thumb instruction set (compact)
-mfloat-abi=hard \ # Hardware FPU
-mfpu=fpv4-sp-d16 \ # FPU tipi
-fno-exceptions \ # Exception devre dışı
-fno-rtti \ # RTTI devre dışı
-fno-threadsafe-statics \ # Static init lock devre dışı (single-thread)
-fno-use-cxa-atexit \ # atexit devre dışı
-Os \ # Boyut optimizasyonu
-Wall -Wextra \
-o firmware.elf main.cpp-fno-exceptions ile derlediğinde throw veya try-catch kullanırsan derleme hatası alırsın. Bu, yanlışlıkla exception kullanımını engeller.
⚠️ Dikkat: -fno-exceptions aktifken, STL container'ların at() metodu gibi exception fırlatan fonksiyonlar tanımsız davranışa neden olabilir. operator[] kullanın ve bounds checking'i kendiniz yapın.
Static Allocation ve Placement New
Dinamik bellek kullanmadan nesne oluşturmanın yolları.
Placement New
placement new, daha önce ayrılmış bellek bölgesinde nesne oluşturur. new operatörü bellek ayırmaz, sadece constructor çağırır.
#include <cstdint>
#include <cstring>
#include <new> // placement new için
// Statik bellek alanı
alignas(16) static uint8_t sensor_memory[sizeof(int) * 4 + 256];
// Basit placement new örneği
class SensorDriver {
public:
SensorDriver(uint32_t address, uint16_t sample_rate)
: hw_address_(address), sample_rate_(sample_rate), initialized_(false) {}
bool init() {
// Hardware register'lara yaz
initialized_ = true;
return true;
}
int32_t read() const {
if (!initialized_) return -1;
auto reg = reinterpret_cast<volatile uint32_t*>(hw_address_);
return static_cast<int32_t>(*reg);
}
~SensorDriver() {
// Hardware'ı kapat
initialized_ = false;
}
private:
uint32_t hw_address_;
uint16_t sample_rate_;
bool initialized_;
};
// Derleme zamanında ayrılmış bellek
alignas(SensorDriver) static uint8_t driver_storage[sizeof(SensorDriver)];
void setup() {
// Placement new: driver_storage alanında SensorDriver oluştur
// Heap KULLANILMAZ — bellek zaten statik olarak ayrılmış
auto* driver = new (driver_storage) SensorDriver(0x40010000, 1000);
driver->init();
auto value = driver->read();
// Explicit destructor çağrısı (placement new ile oluşturulmuş nesnelerde şart)
driver->~SensorDriver();
}Static Object Pool
#include <cstdint>
#include <cstddef>
#include <new>
// Generic statik nesne pool'u — heap kullanmaz
template<typename T, size_t N>
class StaticPool {
public:
T* allocate() {
for (size_t i = 0; i < N; ++i) {
if (!occupied_[i]) {
occupied_[i] = true;
return new (&storage_[i]) T(); // Placement new
}
}
return nullptr; // Pool dolu
}
void deallocate(T* ptr) {
for (size_t i = 0; i < N; ++i) {
if (ptr == reinterpret_cast<T*>(&storage_[i])) {
ptr->~T(); // Destructor çağır
occupied_[i] = false;
return;
}
}
}
size_t available() const {
size_t count = 0;
for (size_t i = 0; i < N; ++i) {
if (!occupied_[i]) ++count;
}
return count;
}
private:
struct alignas(T) Storage {
uint8_t data[sizeof(T)];
};
Storage storage_[N];
bool occupied_[N] = {}; // Hepsi false ile başlar
};
// Kullanım
struct Task {
uint32_t id;
uint8_t priority;
void (*handler)(void);
};
StaticPool<Task, 16> task_pool; // 16 Task kapasiteli, statik bellek
void create_task(uint32_t id, uint8_t priority, void (*handler)(void)) {
Task* task = task_pool.allocate();
if (task) {
task->id = id;
task->priority = priority;
task->handler = handler;
}
// task_pool.available() ile boş slot kontrolü yapılabilir
}Volatile ve Hardware Register Erişimi
volatile keyword'ü, derleyiciye "bu değişkenin değeri senin bilmediğin şekilde değişebilir, optimize etme" der. Embedded'da hardware register'lara erişimde zorunludur.
#include <cstdint>
// Hardware register adresleri (STM32F4 örneği)
struct GPIO_Registers {
volatile uint32_t MODER; // Mode register
volatile uint32_t OTYPER; // Output type
volatile uint32_t OSPEEDR; // Speed
volatile uint32_t PUPDR; // Pull-up/Pull-down
volatile uint32_t IDR; // Input data (READ-ONLY)
volatile uint32_t ODR; // Output data
volatile uint32_t BSRR; // Bit set/reset
volatile uint32_t LCKR; // Lock
volatile uint32_t AFRL; // Alternate function low
volatile uint32_t AFRH; // Alternate function high
};
// GPIO port base adresleri (STM32F4)
constexpr uintptr_t GPIOA_BASE = 0x40020000;
constexpr uintptr_t GPIOB_BASE = 0x40020400;
constexpr uintptr_t GPIOC_BASE = 0x40020800;
// Register erişim sınıfı
class Gpio {
public:
explicit Gpio(uintptr_t base_address)
: regs_(reinterpret_cast<GPIO_Registers*>(base_address)) {}
void set_output(uint8_t pin) {
// MODER register: her pin 2 bit, 01 = output
uint32_t pos = pin * 2;
regs_->MODER &= ~(0x3U << pos); // Temizle
regs_->MODER |= (0x1U << pos); // Output moduna ayarla
}
void write_high(uint8_t pin) {
// BSRR: Bit 0-15 set, Bit 16-31 reset
regs_->BSRR = (1U << pin);
}
void write_low(uint8_t pin) {
regs_->BSRR = (1U << (pin + 16));
}
bool read(uint8_t pin) const {
return (regs_->IDR & (1U << pin)) != 0;
}
void toggle(uint8_t pin) {
regs_->ODR ^= (1U << pin);
}
private:
GPIO_Registers* regs_; // volatile struct'a pointer
};
// Kullanım
void blink_led() {
Gpio portA(GPIOA_BASE);
portA.set_output(5); // PA5 = output (Nucleo board LED)
while (true) {
portA.toggle(5);
// Delay...
}
}Volatile Olmazsa Ne Olur?
// ❌ volatile OLMADAN — derleyici optimize edebilir
uint32_t* status_reg = (uint32_t*)0x40020010;
// Derleyici bu döngüyü kaldırabilir:
// "status_reg hiç değişmiyor, neden kontrol ediyorsun?"
while ((*status_reg & 0x01) == 0) {
// Donanım hazır olana kadar bekle
}
// ✅ volatile İLE — derleyici her okumayı gerçekleştirir
volatile uint32_t* status_reg = (volatile uint32_t*)0x40020010;
// Derleyici her döngüde register'ı GERÇEKTEN okur
while ((*status_reg & 0x01) == 0) {
// Donanım hazır olana kadar bekle
}Derleyici -O2 veya -O3 optimizasyon seviyelerinde agresif optimize eder. volatile olmadan, değişkenin "dışarıdan" değişebileceğini bilemez ve okumayı gereksiz sayabilir.
💡 İpucu: volatile thread safety sağlamaz — sadece "bu değişkene her erişimde gerçekten oku/yaz" demektir. Thread synchronization için std::atomic kullan. Embedded'da volatile, yalnızca hardware register ve interrupt handler ile paylaşılan değişkenler için kullanılır.
MISRA C++ Standartları
MISRA (Motor Industry Software Reliability Association), otomotiv endüstrisinden doğan ama tüm güvenlik kritik yazılımlarda kullanılan kodlama kuralları setidir.
MISRA C++ Temel Kuralları (Seçme)
| Kural | Açıklama | Neden |
|---|---|---|
| Dinamik bellek yasak | new/delete kullanılmaz | Heap fragmentation |
| Exception yasak | throw/try/catch yok | Belirsiz çalışma süresi |
| RTTI yasak | dynamic_cast, typeid yok | ROM tüketimi |
goto yasak | Akış kontrolü yapısal olmalı | Okunabilirlik, doğrulama |
| Örtük tip dönüşümü sınırlı | Explicit cast zorunlu | Veri kaybı riski |
| Signed/unsigned karıştırma yasak | Aynı tip aritmetik | Tuzak davranışlar |
| Union kullanımı kısıtlı | Type punning riski | Tanımsız davranış |
| Recursion yasak/sınırlı | Stack derinliği garanti edilemez | Stack overflow |
#define yerine constexpr | Tip güvenli sabitler | Makro tuzakları |
Statik Analiz ile MISRA Kontrolü
# cppcheck ile MISRA kontrolü
cppcheck --addon=misra --enable=all src/
# clang-tidy ile MISRA benzeri kontroller
clang-tidy -checks='bugprone-*,cert-*,misc-*' src/*.cpp
# Ticari araçlar: Polyspace (MathWorks), Parasoft, PC-lintMISRA kurallarının tamamına uyum genellikle sertifikasyon gerektiren projeler (otomotiv, tıbbi cihaz, havacılık) için zorunludur. Hobi projelerde tamamına uyma gerekli değil ama temel prensipleri bilmek faydalı.
Arduino ve ESP32 ile C++
Embedded C++'ın en erişilebilir giriş noktası Arduino ve ESP32 gibi geliştirme kartlarıdır. Arduino IDE C++ kullanır ama bunu gizler. ESP-IDF ise daha profesyonel bir C++ deneyimi sunar.
Arduino: Gizli C++
// Arduino .ino dosyası aslında C++ dosyasıdır
// setup() ve loop() fonksiyonları main() tarafından çağrılır
// C++ sınıfı kullanımı
class TemperatureSensor {
public:
explicit TemperatureSensor(uint8_t pin) : pin_(pin) {}
float read_celsius() const {
int raw = analogRead(pin_);
// 10-bit ADC: 0-1023 → 0-3.3V → sıcaklık
float voltage = raw * 3.3f / 1023.0f;
return (voltage - 0.5f) * 100.0f; // LM35 formülü
}
private:
uint8_t pin_;
};
// Template kullanımı — derleme zamanında çözülür
template<size_t N>
class MovingAverage {
public:
void add(float value) {
buffer_[index_] = value;
index_ = (index_ + 1) % N;
if (count_ < N) ++count_;
}
float average() const {
if (count_ == 0) return 0.0f;
float sum = 0.0f;
for (size_t i = 0; i < count_; ++i) {
sum += buffer_[i];
}
return sum / static_cast<float>(count_);
}
private:
float buffer_[N] = {};
size_t index_ = 0;
size_t count_ = 0;
};
// Arduino setup/loop
TemperatureSensor sensor(A0);
MovingAverage<10> filter; // 10 örneklik hareketli ortalama
void setup() {
Serial.begin(115200);
}
void loop() {
float temp = sensor.read_celsius();
filter.add(temp);
Serial.print("Anlık: ");
Serial.print(temp);
Serial.print(" °C, Ortalama: ");
Serial.print(filter.average());
Serial.println(" °C");
delay(1000);
}ESP32 ile Modern C++
ESP32, dual-core 240 MHz işlemci ve Wi-Fi/Bluetooth içerir. ESP-IDF framework'ü C++17 destekler ve FreeRTOS üzerinde çalışır.
// ESP-IDF ile C++17 kullanımı
#include <cstdint>
#include <array>
#include <optional>
// constexpr ile derleme zamanı pin konfigürasyonu
struct PinConfig {
uint8_t pin;
bool pullup;
bool output;
};
constexpr std::array<PinConfig, 3> LED_PINS = {{
{2, false, true}, // Dahili LED
{4, false, true}, // Harici LED 1
{5, false, true}, // Harici LED 2
}};
// std::optional ile hata yönetimi (exception yerine)
std::optional<float> read_temperature(uint8_t sensor_id) {
if (sensor_id > 3) return std::nullopt;
// I2C okuma simülasyonu
int32_t raw = 0; // i2c_read(sensor_id)
if (raw == -1) return std::nullopt;
return static_cast<float>(raw) * 0.0625f;
}
// FreeRTOS task wrapper
template<typename Func>
class Task {
public:
Task(const char* name, uint32_t stack_size, uint8_t priority, Func func)
: func_(func)
{
// xTaskCreate(...) ile task oluştur
}
private:
Func func_;
};Bare Metal vs RTOS
Bare Metal
İşletim sistemi yok. Kodun doğrudan donanım üzerinde çalışır. main() fonksiyonu sonsuz döngüde çalışır.
// Bare metal yapı: super loop
int main() {
hardware_init();
while (true) {
read_sensors(); // ~50 us
process_data(); // ~200 us
update_outputs(); // ~30 us
check_uart(); // ~10 us
// Toplam döngü: ~290 us → ~3.4 kHz yenileme hızı
}
}
// Interrupt ile birlikte
volatile bool data_ready = false;
// Interrupt Service Routine (ISR)
extern "C" void TIMER_IRQHandler() {
// ISR: mümkün olduğunca KISA olmalı
data_ready = true; // Flag set et, ağır işlemi main loop'ta yap
}
int main() {
timer_init(1000); // 1 kHz interrupt
while (true) {
if (data_ready) {
data_ready = false;
process_sensor_data();
}
// Diğer işler...
}
}Avantajlar: Basit, tahmin edilebilir zamanlama, minimum overhead. Dezavantajlar: Görevler arasında önceliklendirme yok, karmaşık zamanlamayı elle yönetmek gerekir.
RTOS (Real-Time Operating System)
FreeRTOS, Zephyr, RTEMS gibi gerçek zamanlı işletim sistemleri görev zamanlama, önceliklendirme ve senkronizasyon sunar.
// FreeRTOS ile multi-tasking
#include "FreeRTOS.h"
#include "task.h"
#include "queue.h"
// Kuyruk: ISR → Task veri iletimi
QueueHandle_t sensor_queue;
// Yüksek öncelikli görev: Sensör okuma (her 10ms)
void sensor_task(void* params) {
while (true) {
int32_t value = read_adc();
xQueueSend(sensor_queue, &value, portMAX_DELAY);
vTaskDelay(pdMS_TO_TICKS(10));
}
}
// Orta öncelikli görev: Veri işleme
void process_task(void* params) {
int32_t value;
while (true) {
if (xQueueReceive(sensor_queue, &value, portMAX_DELAY)) {
// Filtreleme, analiz...
int32_t result = apply_filter(value);
update_display(result);
}
}
}
// Düşük öncelikli görev: Logging
void log_task(void* params) {
while (true) {
log_system_status();
vTaskDelay(pdMS_TO_TICKS(1000)); // Her 1 saniye
}
}
int main() {
sensor_queue = xQueueCreate(32, sizeof(int32_t));
xTaskCreate(sensor_task, "Sensor", 256, nullptr, 3, nullptr); // En yüksek
xTaskCreate(process_task, "Process", 512, nullptr, 2, nullptr); // Orta
xTaskCreate(log_task, "Log", 256, nullptr, 1, nullptr); // En düşük
vTaskStartScheduler(); // RTOS başlat — buradan sonra geri dönmez
while (true) {} // Buraya ulaşılmamalı
}Bare Metal vs RTOS Karar Tablosu
| Kriter | Bare Metal | RTOS |
|---|---|---|
| Karmaşıklık | Düşük | Orta-Yüksek |
| Görev sayısı | 1-3 basit görev | 3+ bağımsız görev |
| Zamanlama | Belirleyici (deterministik) | Scheduler yönetir |
| RAM kullanımı | Minimum | +2-10 KB (kernel + task stack) |
| Önceliklendirme | Yok | Var (preemptive) |
| Senkronizasyon | Manuel (volatile flag) | Mutex, semaphore, queue |
| Uygun projeler | LED blink, basit sensör | IoT gateway, robot kontrolü |
⚠️ Dikkat: RTOS kullanmak, gerçek zamanlı garanti vermek demek değildir. RTOS, görevleri zamanlama altyapısı sağlar ama her görevi doğru öncelikle yapılandırmak, deadline'ları doğrulamak ve worst-case execution time (WCET) analizi yapmak mühendise düşer.
Özet
Embedded C++, dilin zero-cost abstraction'larını kullanarak C'nin güvenlik eksikliklerini kapatır —
enum class,constexpr, templates, RAII sıfır runtime maliyetle tip güvenliği sağlar.Exception, RTTI ve dinamik bellek tahsisi embedded'da genellikle kapatılır (
-fno-exceptions,-fno-rtti) — belirsiz zamanlama ve kaynak tüketimi gerçek zamanlı sistemlerde kabul edilemez.Static allocation ve placement new, heap kullanmadan nesne yönetimi sağlar — object pool pattern'ı ile sabit boyutlu, fragmentasyon-free bellek yönetimi yapılır.
`volatile` keyword'ü, hardware register ve interrupt değişkenlerinde derleyici optimizasyonunu engeller — onsuz derleyici kritik okumaları atlayabilir.
Bare metal basit, tahmin edilebilir sistemler için idealdir; RTOS ise çoklu görev, önceliklendirme ve senkronizasyon gereken projeler için altyapı sağlar.
Arduino ve ESP32, embedded C++ öğrenmeye başlamak için en erişilebilir platformlardır — modern C++17 özellikleri (constexpr, optional, array) bu kartlarda kullanılabilir.
AI Asistan
Sorularını yanıtlamaya hazır