Çoğumuz, Arduino mikrodenetleyicilerimizdeki belleğin, kodu depolayıp çalıştırmamızı sağlayan temel bir parça olduğunu genel hatlarıyla biliyoruz. Bu anlayış, basit programlarla çalışıyorsak genellikle yeterlidir! Ancak, TinyML gibi daha gelişmiş bir uygulama oluşturmaya çalıştığımızda, Arduino belleği hakkında daha derin bir anlayış, sevdiğimiz mikrodenetleyicilerden en iyi şekilde yararlanmamıza yardımcı olabilir. Neyse ki, bu makale tam olarak bunu sağlayacak!
Aşağıdaki içerikleri ve daha fazlasını ele alacağız!
- Arduino belleğini neden bilmelisiniz?
- Arduino’da Bellek Nedir?
- Arduino Bellek Kullanımını Nasıl Ölçeriz
- Arduino’da Bellek Kullanımını Nasıl Optimize Ederiz
- Bellek Yoğun Projeler için Arduino’lar

Arduino Belleğini Neden Bilmelisiniz?
Genel ve basit terimlerle, Arduino mikrodenetleyicilerindeki bellek bloklarının amacı, çalışma zamanı verilerini veya bilgileri geçici veya kalıcı olarak depolamaktır. Örneğin, Arduino’ya yüklediğiniz kod ve o kodda tanımlanan değişkenler bellekte saklanır. Aslında, bellek her türlü bilgisayarın temel bir bileşenidir!
Arduino gibi mikrodenetleyiciler, belirli amaçlara hizmet etmek için küçük ve uygun fiyatlı olarak tasarlanmıştır ve bu nedenle nispeten sınırlı hesaplama kaynaklarına sahiptir. Modern bilgisayarlarla karşılaştırıldığında, bu bilgisayarlar genellikle Gigabayt (109) bellek kapasitesine sahipken, mikrodenetleyiciler Kilobayt (103) ile birkaç Megabayt (106) arasında bellek boyutlarıyla çalışır. Bu nedenle, Arduino’muzdaki bellek kaynaklarını dikkatli bir şekilde kullanmak önemlidir.
Bellek iyi yönetilmediğinde, Arduino’nuz çeşitli şekillerde başarısız olabilir. Bazen, bu, yukarıda gösterildiği gibi kodun kartınıza yüklenmemesi kadar belirgin olabilir. Diğer durumlarda, her şey bir süre düzgün çalışıyormuş gibi görünebilir, ancak mikrodenetleyici daha sonra yanıt vermeyi durdurur – bu çok daha karmaşık!
Her durumda, arızalı bir kartla çalışmadığınız sürece, derlenen ancak beklenildiği gibi çalışmayan herhangi bir kodun bir bellek sorunu yaşadığı neredeyse kesindir. Bu olduğunda, sorunu teşhis edip çözebilmek için arka planda neler olduğunu anlamak önemlidir!
Arduino’da Bellek Nedir?
Bilmeniz gereken üç tür Arduino belleği vardır:
- Flash veya Program Belleği (PROGMEM)
- SRAM – Statik Rastgele Erişim Belleği
- EEPROM – Elektronik Olarak Silinebilir Programlanabilir Salt Okunur Bellek
Flash Bellek
Flash bellek, USB bellek sürücüleri ve SD kartlarda gördüğümüz depolama için kullanılan bir bellek türüdür. Volatildir, yani güç sağlanmadığında bile depolanan bilgileri korur.
Bir Arduino’da, Flash program kodunu ve ek verileri depolamak için kullanılır. Flash bellekte tutulan veriler, kod çalıştırılmadan önce SRAM’a kopyalanır, çünkü bu veriler kod çalıştırılarak değiştirilemez.
SRAM
SRAM, Statik Rastgele Erişim Belleği’nin kısaltmasıdır ve Arduino’daki bellek sorunlarını teşhis etmenin en önemli bileşenidir. Bunu, üç ana bileşen arasında paylaşılan bir bellek bloğu olarak düşünebilirsiniz: Statik Veri, Heap & Stack.
- Statik Veri – SRAM’in bu bölümü, programda değişmeyen verileri, örneğin global ve statik değişkenleri depolar.
- Heap – Heap, statik verinin yanında bulunur ve kod çalıştırılarak oluşturulan değişkenler gibi dinamik olarak tahsis edilen veri öğeleri için kullanılır.
- Stack – Stack, fonksiyon parametrelerini, yerel değişkenleri, kesmeleri ve fonksiyon çağrılarını takip etmek için kullanılır. Her fonksiyon çağrısı, stack’in boyutunu artırırken, bir fonksiyondan dönmek, o belleği serbest bellek havuzuna geri döndürür.
Stack ve heap’in serbest belleğin zıt uçlarında bulunduğunu fark etmiş olabilirsiniz. Her biri büyüdükçe, serbest belleğin daha fazla kısmını tüketirler ve etkili bir şekilde “birbirlerine doğru hareket ederler”. Çoğu bellek sorunu, stack ve heap’in “çarpışmasından” kaynaklanır ve bu, bellekte tutulan verilerin bozulmasına neden olabilir. Daha önce belirtildiği gibi, bazı bozulmalar anında bir çöküşe neden olabilir veya kod bir süre daha çalışmaya devam edebilir, ardından sorunlar ortaya çıkabilir. Bu duruma bağlıdır!
EEPROM
Flash’a benzer şekilde, EEPROM da veri okumak ve yazmak için kullanabileceğiniz başka bir volatıl bellek türüdür. Ancak, bunu byte byte yapmanız gerekecek, bu da genellikle alışık olduğumuzdan biraz daha zahmetli olabilir. Bunu, hem flash hem de SRAM arasında bir yerde, okunabilir/yazılabilir flash veya volatıl SRAM olarak düşünebilirsiniz!
Not: Çoğu EEPROM’un yazma/silme döngüsü ömrü yaklaşık 100,000’dir, bu nedenle EEPROM okuma/yazma işlemlerini döngüler içinde kullanırken dikkatli olun!
Arduino Bellek Kullanımını Nasıl Ölçeriz
Optimizasyonlardan önce, programımızın kullandığı bellek miktarını ölçerek teşhisimize başlamalıyız.
Flash
Flash belleği ölçmek oldukça kolaydır – aslında, Arduino IDE bunu sizin için yapacaktır! Kodunuzu derlediğiniz veya yüklediğiniz her seferde, IDE, yüklemeniz tarafından kullanılan bellek miktarını ve seçilen kartın belleğinin ne kadarını kullandığını tam olarak gösterir. Örneğin, aşağıda yüklediğim sketch, Wio Terminal’in flash belleğinin sadece 35K’sını veya %7’sini kullanıyor – oldukça rahat!
EEPROM
EEPROM’a byte byte yazmanız gerektiğinden, hangi adreslerin kullanıldığını tam olarak bilmelisiniz. Şüphe durumunda, kodunuzu iki kez kontrol etmelisiniz! Makalemizin ana odak noktası olmasa da, EEPROM ile veri okuma ve yazma örneği aşağıda referans için gösterilmiştir. Ayrıca, Arduino’da EEPROM’u nasıl kullanacağınızı resmi belgelerden öğrenebilirsiniz!
// Belirtilen adrese veri yaz
#include <EEPROM.h>
EEPROM.write(address, value);
EEPROM.read(address);
SRAM
Arduino’nun SRAM kullanımını ölçmek için, bu arduino kütüphanesinden kullanışlı bir fonksiyon çağrısı olan freeMemory() fonksiyonunu kullanabiliriz; bu fonksiyon, mevcut serbest RAM’i ölçer ve aşağıda tanımlanmıştır.
#ifdef __arm__
// sbrk'ı tanımlamak için uinstd.h kullanılmalı ama Due bir çakışmaya neden oluyor
extern "C" char* sbrk(int incr);
#else // __ARM__
extern char *__brkval;
#endif // __arm__
int freeMemory() {
char top;
#ifdef __arm__
return &top - reinterpret_cast<char*>(sbrk(0));
#elif defined(CORE_TEENSY) || (ARDUINO > 103 && ARDUINO != 151)
return &top - __brkval;
#else // __arm__
return __brkval ? &top - __brkval : &top - __malloc_heap_start;
#endif // __arm__
}
SRAM yönetimindeki amacın yığın (heap) ve yığın (stack) arasında bir çakışmayı önlemek olduğunu unutmayın. Bu nedenle, freeMemory() fonksiyonunun aslında bize sağladığı şey, aralarındaki mevcut boş bellek miktarıdır.
Yığın ve yığın boyutları program yürütülmesi boyunca değişeceğinden (yani dinamik olduklarından), kodun çeşitli noktalarında mevcut boş belleği izlemek için freeMemory() fonksiyonunu düzenli olarak çağırmak da önemlidir.
En Büyük Bellek Suistimalleri
Belleği optimize etme çabalarımıza rağmen, bazı cihazlar ve sürücüler işlev görmek için daha fazla SRAM gerektirecektir. Bu durumlarda, suistimalleri tanımlamak ve bunların etrafında çalışmak önemlidir!
Dosya Sistemleri
Eğer Arduino’nuz bir SD veya MicroSD kart ile arayüz sağlıyorsa, veri okuma ve yazma işlemlerini kolaylaştırmak için 512 baytlık büyük bir bellek tamponu ayırmanız gerekecektir. Mümkünse, programınızın içeriğini flaş belleğe taşımanız önerilir, çünkü bu da daha hızlı olacaktır.
Piksellerle İlgili Her Şey
OLED ekranlar, RGB ışıklar, ne derseniz – bu şeyler bellek tüketir! Her piksel, Kırmızı, Yeşil, Mavi (RGB) değerlerinin bir kombinasyonu olarak tanımlanır ve 3 bayt SRAM tüketir. Bu sayıyı küçümsemeyin, çünkü küçük ekranlar bile kolayca binlerce piksele sahip olabilir! Elbette, monokrom (tek renk) ekranlar her 8 piksel için yalnızca 1 bayt gerektirir, ancak bu, 128’e 64 boyutundaki bir ekran için hala 1K SRAM demektir – dikkatli seçin!
TinyML
TinyML, makine öğrenimini küçük ve maliyet etkin mikrodenetleyicilere getirmeyi amaçlayan yeni bir kavramdır. Çoğu makine öğrenimi masaüstü sınıfı bilgisayarlarda yapıldığından, bu durum mikrodenetleyicilerde bellek tüketimini artırdığına şüphe yoktur. Kenar ML uygulamaları geliştirmek istiyorsanız, bellek tüketimine daha da dikkat etmeniz gerekecek çünkü ML modelinin etrafında çalışmak zorundasınız.
Kenar ML hakkında daha fazla bilgi edinmek istiyorsanız, önceki makalemizi buradan okumanızı şiddetle tavsiye ederim.
Arduino’da Bellek Kullanımını Optimize Etme
Eğer programınız bir bellek problemi nedeniyle başarısız oluyorsa, şanslısınız. Her tür Arduino belleği için, kullandığımız bellek miktarını azaltmak amacıyla kodumuzda yapabileceğimiz birkaç temel değişiklik vardır. Biraz ustalıkla, bellek sınırlarının altına tekrar inebiliriz! Bu bölümde, yalnızca flaş ve SRAM’ı optimize etmekten bahsedeceğiz, çünkü EEPROM belleği genellikle oldukça basittir.
Not: Bellek optimizasyonu, bilgisayar dünyasında derin ve ileri bir konudur; bu konuda daha derin bilgi edinmek kesinlikle sizi daha ileri götürebilir! Bu makalede paylaşılan adımlar, başlangıç seviyesindeki kullanıcıların kodlarını optimize etmek için atabileceği bazı adımlardır!
Flaş Belleği Optimize Etme
Programınızın boyutunu azaltmanın en iyi yolu, hangi parçalarının gerçekten gerekli olduğunu belirlemek ve gereksiz olanları ortadan kaldırarak yer kazanmaktır. Örneğin:
- Kullanılmayan kütüphaneleri, fonksiyonları ve değişkenleri ortadan kaldırın.
- Erişilemeyen kodlara dikkat edin, örneğin asla doğru olmayacak koşullar.
- Tekrarlayan kodları yeniden kullanılabilir bir fonksiyon içine alarak birleştirin.
Aşırı durumda, daha fazla yer kazanmak için bootloader’ı ortadan kaldırmayı düşünebilirsiniz. Ancak, bootloader’ların geliştirme süreçlerinde birkaç önemli işlevi olduğunu ve hayatınızı kolaylaştırabileceğini öneririm. Yine de bunu yapmak istiyorsanız, bootloader programlama makalemize göz atın.
SRAM’ı Optimize Etme
SRAM, kullanımı en karmaşık bellek türüdür, ancak onu optimize etme konusunda daha fazla seçeneğiniz de vardır.
Davranışları Anlayın
SRAM yönetiminin bazı başlangıç kullanıcılarını karıştırabilecek önemli bir yönü yığın ile ilgilidir. Yığının programda dinamik olarak tahsis edilen değişkenler için kullanıldığını biliyoruz, ancak dikkatli kullanılmadığında ortaya çıkan önemli bir sorun vardır ki buna yığın parçalanması denir. Bunu anlamak için bir yığın illüstrasyonuna bakalım.
Tüm yığın 64KB bellek tutar. 3. Adıma kadar, ardışık tahsisler komşu bellek adreslerini kaplar, bu oldukça basittir. Şimdi, ikinci tahsisin serbest bırakıldığında ne olduğunu gözlemleyin. Artık teorik olarak 2. Adımda olduğu gibi 32KB boş belleğe sahip olsak da, sonraki herhangi bir tahsisin maksimum boyutu artık 32KB yerine 16KB’dir! Bu durumda, ikinci tahsisin serbest bırakılmasından elde edilen bellek gömülü yığın alanı olarak bilinir ve yığın parçalanması meydana gelmiştir.
Gömülü yığın alanı, yığın tarafından kullanılamaz, ancak sonraki yığın tahsisleri için kullanılabilir. Bu nedenle, kötü yığın yönetimi yığının hızla yığına doğru büyümesine neden olabilir ve bellek bozulmasını hızlandırabilir!
Yerel Değişkenler Kullanın
Yığın sorununu aşmanın iyi bir yolu, fonksiyonlarınızda yerel değişkenler kullanmaktır. Yerel değişkenler, bir fonksiyon içinde tanımlanan ve yalnızca o fonksiyon içinde kullanılabilen değişkenlerdir. Bu şekilde, bellek kullanımı yığın yerine yığın parçasının bir parçası haline gelir. Bunun avantajı, yığın tarafından kullanılan belleğin fonksiyon geri döndüğünde tamamen serbest bırakılmasıdır, bu da kodumuzun aynı şekilde çalışmasını sağlar ve yığın parçalanmasından kaynaklanan zayıflıklara açılmasını önler!
Flaş / PROGMEM’e Yükleme
Normalde, kodumuz statik değişkenleri dinamik olarak SRAM’a yükler, bu da yığın içinde değerli belleği israf eder çünkü onları asla değiştirmeyeceğiz. Neyse ki, programımıza bu tür değişkenleri SRAM’dan çıkarmasını ve bunun yerine doğrudan flaş belleğinden referans almasını söylemenin birkaç yolu vardır.
Dizeler için:
Literal dizeler çok fazla bellek tüketir, ancak bellek kullanımını azaltmanın kolay bir yolu vardır. Aşağıda gösterildiği gibi dizeleri F() makrosuyla sarmalayarak, programımıza dizenin Flash’ta saklanmasını söyleriz, bu da bize çok değerli SRAM kazandırır!
Serial.println(F(“Bu çok fazla bellek tüketen bir dizidir, ama artık değil!”));
Diğer Veriler için:
Ayrıca, PROGMEM modifier kullanarak diğer veri türleri için de benzer bir şey yapabilirsiniz. Veriler Flash belleğe taşındıktan sonra, verileri okumak ve yazmak için pgmspace.h kütüphanesinde tanımlanan özel fonksiyonları kullanmanız gerekecektir. Bu, biraz rahatsızlık yaratıyor gibi görünebilir, ancak SRAM tüketimini azaltmak için harika bir yöntemdir!
Reserve() Bellek
reserve() fonksiyonu, gelecekte büyüyebilecek bir dize için bir tampon oluşturur. Bu şekilde, program dizeyi değiştirdiğinde belleği yeniden tahsis etmek zorunda kalmaz.
Bunun önemi nedir? Dize değiştirildiğinde, işlemi kolaylaştırmak için genellikle ara değişkenler oluşturulur. Bu olduğunda, yığın bellek tahsisi karmaşık hale gelir ve nihai dize nesnesi için genellikle yeni bir bellek bölümü tahsis edilmesi gerekir. Bu, yığın parçalanması için fırsatlar yaratır ve programımızın bellek verimliliğini azaltır!
reserve() kullanmak için aşağıdaki sözdizimini takip edebilirsiniz. Daha fazla bilgi resmi belgede de bulunabilir.
myString.reserve(size);
// burada myString String türünde bir değişkendir
// tahsis edilecek bellek boyutunu (unsigned int) belirtir.
Tampon Boyutlarını Değiştirin
reserve() ile yapabileceğimiz gibi, arka planda çalışan kodumuzun farklı bileşenleri bellek tüketimini yönetmek için tamponlar kullanır. Ancak, tahsis edilen tamponlar bazen belirli kullanım durumunuz için aşırı olabilir. Ekstra bellek boşaltmanız gerekiyorsa, tampon boyutlarını değiştirmek faydalı bir seçenek olabilir.
Kendi Tamponlarınız – Tahsis ettiğiniz tamponların boyutlarını kontrol etmek gerektiğini söylemeye gerek yok. Gerekenden daha büyük olmamalıdırlar!
Kütüphaneler – Bazı kütüphaneler, bileşenlerinin sorunsuz çalışmasına yardımcı olmak için arka planda tamponlar oluşturur. Kütüphane kodunu okumak için sabrınız varsa, bu bellek tüketimini azaltmak için bir fırsat olabilir.
Sistem Tamponları – Farklı sistemler, 64 baytlık seri alma tamponu gibi çeşitli arka uç hizmetleri için tamponlar tahsis eder. Yüksek hızlı seri iletişim kullanmayı düşünmüyorsanız, Arduino kurulumunuzdaki HardwareSerial.h dosyasında tanımlanan tampon boyutunu aşağıdaki satırı değiştirerek azaltabilirsiniz:
#define SERIAL_BUFFERSIZE 64
Doğru Veri Türlerini Kullanın
Farklı veri türleri farklı miktarlarda bellek kullanır! Mümkünse en küçük veri türünü kullanarak kodunuzun kullandığı bellek miktarını büyük ölçüde azaltabilirsiniz. Örneğin, bir tamsayı yerine bir byte, bir float yerine de bir tamsayı kullanın!
Arduino Önerileri
En kötü durumda, Arduino kartınızın sahip olduğu fiziksel bellek, inşa etmeye çalıştığınız uygulama için yeterli olmayabilir. Neyse ki, Seeed, işinizi görmek için yeterli güç ve bellek sağlayacak birçok Arduino uyumlu mikrodenetleyici kartı sunmaktadır!
Seeeduino XIAO
Seeeduino XIAO, Seeeduino Ailesi’ndeki en küçük Arduino uyumlu karttır. Küçük boyutuna rağmen, Seeeduino XIAO güçlü SAMD21 mikroçipi ve çeşitli donanım arayüzleri ile donatılmıştır. 256KB Flash ve 32KB SRAM ile Seeeduino XIAO, popüler Arduino UNO’dan 16 kat daha fazla SRAM barındırmaktadır!
Ürün Özellikleri:
- 256KB Flash, 32KB SRAM ile ARM Cortex-M0+ 32bit 48MHz mikrodenetleyici (SAMD21G18)
- Arduino IDE & MicroPython ile uyumlu
- Kolay Proje İşlemi: Breadboard dostu
- Küçük Boyut: Giyilebilir cihazlar ve küçük projeler için parmak büyüklüğünde (20×17.5mm)
- 11 dijital/analog pin, 10 PWM Pin, 1 DAC çıkışı, 1 SWD Bağlantı noktası arayüzü, 1 I2C arayüzü, 1 UART arayüzü, 1 SPI arayüzü
Seeeduino XIAO hakkında daha fazla bilgi edinmek ister misiniz? Şimdi ürün sayfasını ziyaret edin!
Wio Terminal
Wio Terminal, ATSAMD51 tabanlı tam bir Arduino geliştirme platformudur ve Realtek RTL8720DN ile güçlendirilmiş kablosuz bağlantıya sahiptir. Tümleşik bir mikrodenetleyici olan Wio Terminal, 2.4” LCD Ekran, IMU, mikrofon, buzzer, microSD kart yuvası, ışık sensörü ve kızılötesi verici ile donatılmıştır. 4MB flash bellek ve 192KB RAM ile, bellek yoğun kullanımlar için mükemmel bir adaydır, örneğin TinyML!
Ürün Özellikleri:
- Güçlü MCU: 120MHz’de çalışan ARM Cortex-M4F çekirdekli Microchip ATSAMD51P19
- Güvenilir Kablosuz Bağlantı: Realtek RTL8720DN ile donatılmış, çift bant 2.4GHz / 5GHz Wi-Fi (sadece Arduino tarafından desteklenir)
- Yüksek Entegre Tasarım: 2.4” LCD Ekran, IMU ve yerleşik mıknatıslar & montaj delikleri ile kompakt kasa
- Raspberry Pi 40-pin Uyumlu GPIO
- IoT ile keşfetmek için 300’den fazla tak-çalıştır Grove modülü ile uyumlu
- USB OTG Desteği
- Arduino, CircuitPython, Micropython, ArduPy, AT Firmware, Visual Studio Code desteği
- TELEC Sertifikalı
Wio Terminal almakla ilgileniyorsanız, lütfen ürün sayfasını ziyaret edin!
Özet
Bugünkü Arduino belleği yönetimi makalesinin sonuna geldik! Bu, Arduino’daki farklı bellek türlerini anlamak ve bunları daha iyi kullanmanın çok basit bir tanıtımıydı. Unutmayın, bu öneriler sadece buzdağının görünen kısmıdır ve bellek kullanımını optimize etmenin daha birçok yolu vardır, örneğin kod yazımının alan karmaşıklığını anlamak! Her durumda, nereden başlayacağınız konusunda daha iyi bir fikir edinmiş olmanızı umuyorum!
Daha fazla bilgi edinmek isterseniz, aşağıdaki içerikleri okumanız faydalı olabilir:
- Edge AI – Nedir ve Edge IoT için ne yapabilir?
- Arduino Bootloader Programlama – ARM Mikrodenetleyicileri ile Başlarken
- Arduino ile Çoklu Görev – Millis(), RTOS & Daha Fazlası!
- RTOS Temelleri: Mikrodenetleyicilerle Başlarken
