ghiyatsa— Software Developer

FreeRTOS dual-core di ESP32 — pelajaran dari proyek IoT

20 May 2026·5 min read·#iot#esp32#freertos#c++

Proyek IoT Room Safety Dashboard awalnya berjalan di single task — satu loop besar yang membaca sensor, mem-publish ke MQTT, dan menangani notifikasi Telegram secara berurutan. Ia bekerja. Sampai tidak.

Masalah yang muncul

Saat koneksi MQTT terputus, reconnect bisa memakan waktu 2-5 detik. Selama itu, loop utama berhenti — sensor tidak dibaca, aktuator tidak diperbarui, alarm tidak berbunyi. Untuk sistem keamanan ruangan, ini tidak bisa diterima.

FreeRTOS dual-core

ESP32 punya dua core Xtensa LX6. FreeRTOS yang tertanam di ESP32 Arduino framework memungkinkan kita pin task ke core tertentu:

cpp
// Core 0: sensor polling + aktuator — tidak boleh diblokir network
xTaskCreatePinnedToCore(
    sensorTask,   // fungsi task
    "sensors",    // nama (untuk debugging)
    4096,         // stack size
    NULL,         // parameter
    1,            // prioritas
    NULL,         // handle (tidak perlu)
    0             // core ID
);

// Core 1: MQTT + Telegram + OTA update
xTaskCreatePinnedToCore(
    networkTask,
    "network",
    8192,         // lebih besar karena TLS overhead
    NULL,
    1,
    NULL,
    1
);

Berbagi data antar core

Dua task yang berjalan paralel tidak bisa baca-tulis variabel global sembarangan. Race condition di embedded system lebih susah di-debug daripada di server — tidak ada stack trace yang mudah dibaca.

Solusinya: SemaphoreHandle_t untuk mutual exclusion, atau lebih sederhana, QueueHandle_t untuk passing data searah dari sensor ke network task.

cpp
QueueHandle_t sensorQueue = xQueueCreate(10, sizeof(SensorData));

// Di sensorTask:
SensorData data = readAllSensors();
xQueueSend(sensorQueue, &data, 0); // non-blocking

// Di networkTask:
SensorData data;
if (xQueueReceive(sensorQueue, &data, pdMS_TO_TICKS(100))) {
    publishToMQTT(data);
}

Hasilnya

Sensor tetap dibaca setiap 500ms meski network task sedang reconnect. Alarm berbunyi tepat waktu. Buzzer tidak pernah terlambat lagi karena menunggu acknowledgement dari HiveMQ.

Pelajarannya bukan tentang optimisasi — ini tentang memisahkan concern yang memang punya kebutuhan timing berbeda.