Bu rehber herhangi bir framework kullanmadan sadece GCC derleyicisi ve datasheet kullanarak mikrodenetleyici programlamayı arzulayan geliştiriciler için yazılmıştır. Rehber, Cuce, Keil, Arduino gibi araçların temelinde nasıl çalıştığını ana hatlarıyla açıklamayı amaçlamaktadır.
Bu rehberdeki her bölüm, işlevsellik ve eksiksizlik açısından kademeli olarak ilerleyen kaynakları içerir. Özetle, farklı mimarilerdeki projeleri sıfırdan anlatacağız.
mkdir(),readdir(),fopen() gibi fonksiyonları implemente eder. Cihaz boot sayısını bir dosyada tutar, her boot'ta arttırır ve düzenli olarak yazdırır.| Kart | Arch | MCU datasheet | Board datasheet | Örnek proje |
|---|---|---|---|---|
| STM32 Nucleo-F429ZI | Cortex-M4 | mcu datasheet | board datasheet | blinky, cli, webui |
| STM32 Nucleo-F303K8 | Cortex-M4 | mcu datasheet | board datasheet | lfs |
| STM32 Nucleo-L432KC | Cortex-M4 | mcu datasheet | board datasheet | blinky, cli, lfs |
| TI EK-TM4C1294XL | Cortex-M4F | mcu datasheet | board datasheet | webui |
| RP2040 Pico-W5500 | Cortex-M0+ | mcu datasheet | board datasheet | webui |
| ESP32-C3 | RISCV | mcu datasheet | blinky |
Bu öğreticide Nucleo-F429ZI geliştirme kartını kullanacağız bu yüzden mikrodenetleyicinin ve kartın datasheet'lerini indirmeyi unutmayın.
Ben Sergey Lyubka, mühendis ve girişimciyim. Ukrayna Kyiv State üniversitesinde fizik lisansı yapıyorum . İrlanda Dublin merkezli Cesanata teknoloji şirketinin kurucu ortağı ve yöneticisiyim. Cesanata'nın geliştirdiği bazı gömülü çözümler:
Gömülü ağ programlama konusundaki ücretsiz web seminerime davetlisiniz.
Çalışmalara devam edebilmek için şunlar gereklidir :
Terminalinizi açın ve şu komutu çalıştırın:
$ /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
$ brew install gcc-arm-embedded make stlink git
Terminalinizi açın ve şu komutu çalıştırın:
$ sudo apt -y update
$ sudo apt -y install gcc-arm-none-eabi make stlink-tools git
c:\tools klasörünü oluşturun.bin/st-flash.exe dosyasını c:\tools içine çıkartın.bin/make.exe dosyasını c:\tools içine çıkartın.c:\tools klasörünü Path ortam değişkenine ekleyin.An itibariyle tüm gerekli araçlar yüklendi, terminali ya da komut istemcisini açın ve aşağıdaki komutla bu projeyi indirin ve örneği derleyin.
git clone https://github.com/cpq/bare-metal-programming-guide
cd bare-metal-programming-guide/steps/step-0-minimal
make
mikrodenetleyiciler (uC, veya MCU) özünde küçük bilgisayarlardır. Genellikle CPU, RAM, kodun yükleneceği flash ve bir avuç pin içerirler. Bazı pinler kontrolcüye güç sağlamak için kullanılır, bunlar çoğunlukla GND (topraklama) ve VCC pini olarak işaretlenir. Diğer pinler ise yüksek(high) ve alçak(low) voltaj vererek kontrolcü ile haberleşmek için kullanılır. Haberleşmeden kastedilenlerden en basiti LED yakmaktır. LED'in bir ayağı GND'ye diğer ayağı ise akım sınırlayıcı direnciyle birlikte bir sinyal pinine takılır. Yazılım sinyal pinini low ve high yaparak LED'i yakıp söndürür.
Kontrolcü 32-bit'lik adreslenebilir bölge(region)'lere bölünmüştür. Mesela bazı bellek bölümleri kontrolcünün dahili flash'ının spesifik adresleri ile eşlenmiştir. Firmware kodu bu bölgeyi kullanarak komutları okur ve çalıştırır. Diğer bir bölüm ise başka bir spesifik adresle eşlenmiş olan RAM'dir. RAM bölgesine istediğimiz herhangi bir değeri okuyup yazabiliriz.
STM32F429 datasheet'inin 2.3.1 bölümünü incelediğimizde RAM'in 0x20000000 adresinden başladığını ve 192KB genişliği bulunduğunu anlarız. 2.4 numaralı bölümde flash'ın ise 0x08000000 adresi ile eşlendiğini görebiliriz. mikrodenetleyicimiz 2MB'lık flash'a sahip olduğuna göre RAM bölgesi şöyle konumlandırılmıştır:
Datasheet'te baktığımızda bunlardan daha fazla bellek bölgesi olduğunu da fark ederiz 2.3 numaralı "Memmory Map" bölümünde bunların adres aralıkları verilmiştir. Örnek olarak "GPIOA" bölgesi 0x40020000 adresinden başlayım 1KB uzunluğa sahiptir.
Bu bellek bölgeleri, MCU içindeki farklı "çevre birimlerine" karşılık gelir
Birden fazla çevre birimi bulunmaktadır. Bunlardan en basiti MCU'nun pinlerini "output mode"(çıktı modu) olarak ayarlayıp pine high veya low voltaj vermemizi veya "input mode"(girdi modu) olarak ayarlayıp pine uygulanan voltajı okumamızı sağlayan GPIO(genen amaçlı girdi çıktı)'dur. Seri haberleşme protokolünü kullanarak sadece iki pin ile seri veri almamıza(recive) ve iletmemize(transmit) olanak sağlayan UART çevre birimi de örnek verilebilir. Bunlar dışındada birsürü birim vardır.
Sıklıkla çevre birimlerinin birden fazla örneği,varyasyonu bulunur. Mesela, GPIOA, GPIOB MCU'nun farklı pinlerini kontrol ederler. Aynı şekilde UART1, UART2 de farklı UART kanallarını implemente ederler.Nucleo-F429'de, birden fazla GPIO and UART çevre birimi bulunur.
GPIOA 0x40020000 adresinden başlar,bölüm 8.4'te GPIO register'larının açıklamalarına ulaşabilirsiniz
Datasheet'in söylediğine göre GPIOA_MODER register'ının offset'i 0'dır,bunun anlamı
register'ın adresi 0x40020000 + 0'dir ve register'ın formatı şu şekildedir:

Datasheet'te 32-bit MODER register'larının toplamda 16 olacak şekilde 2-bit'lik veriler tuttuğunu görebilirsiniz. Öyleyse bir MODER register'ı 0.pin için 0 ve 1 bitleri, 1.pin için 2 ve 3 bitleri şeklinde devam ederek 16 fiziksel pini kontrol edebilir. 2 bitlik pinin modununa göre 0 girdiyi(input), 1 çıktıyı(output), 2 özel fonksiyonu (alternate function) -başka bir yerde açıklanan özel işlev- ve 3 ise analog modu ifade eder. Pinler ise bulunduğu bölgeye uygun yani GPIOA için "A0", "A1" veya GPIOB için "B0", "B1" şeklinde adlandırılırlar.
Eğer MODER register'ına 32 bit boyunca 0 değerini yazarsak A0'dan A15'e kadar 16 pini de
input moduna göre ayarlamış oluruz.
* (volatile uint32_t *) (0x40020000 + 0) = 0; // A0-A15 arasını input olarak ata
volatile anahtar kelimesini aklınızda tutun bunun anlamına daha sonra değineceğiz.Bitleri
tek tek değiştirerek sadece istediğimiz pinlere mod atayabiliriz. Örnek olarak A3 pinini "output"
olarak ayarlayalım.
* (volatile uint32_t *) (0x40020000 + 0) &= ~(3 << 6); // 6-7 aralığını temizle
* (volatile uint32_t *) (0x40020000 + 0) |= 1 << 6; // 6-7 aralığını 1 ata
Gelin bu bit işlemlerini birlikte inceleyelim. Amacımız, GPIOA çevre biriminin 3.pininden sorumlu olan bit 6-7'yi belirli bir değere (bizim durumumuzda 1) olacak şekilde atamaktır. Bu işlem iki adımda yapılır. İlk olarak, 6-7 bitlerinin mevcut değerini silmeliyiz, çünkü daha önceden içinde tuttuğu değer işimizi bozabilir. Ardından 6-7 bitlerini istediğimiz değere ayarlamalıyız.
Bundan dolayı,ilk önce 6. ve 7. bitleri 0 yapmalıyız.Peki bir sayının belirli bitlerini nasıl sıfır yaparız? Dört adımla şöyle:
| İşlem | İfade | Bitler (32 bitin ilk 12'si) |
|---|---|---|
N tane yan yana biti alın: 2^N-1, N=2 |
3 |
000000000011 |
| O sayıyı X kere sola kaydırın | (3<<6) |
000011000000 |
| Sayıyı tersleyin: Birler sıfır, sıfırlar bir olacak | ~(3<<6) |
111100111111 |
| Sayıyı bitsel VE(AND) işlemine tabi tutun | VAL &= ~(3<<6) |
xxxx00xxxxxx |
Son adımı aklınızda tutun, bitsel AND işlemi X yerindeki N tane biti sıfırlar (çünkü 0 ile AND'lendi) ama geri kalan bitlere dokunmaz(çünkü 1 ile AND'lendi. Kendisi neyse yeni değeri de o kalacak). Kalan verilere dokunulmaması çok önemlidir çünkü iki veriyi değiştirmek isterken önceden atanan diğer verileri değiştirmek sistemimizi bozacaktır. Özetle
$ claude mcp add bare-metal-programming-guide \
-- python -m otcore.mcp_server <graph>