Arm 2: Stm32 RCC register ve clock ayarları

Merhaba arkadaşlar bugün Arm serimize clock ayarlarını yaparak devam edeceğim. Önceki yazımda Stm32 için linux ortamına nasıl setup kurabiliriz onu anlatmıştım. Önceki yazımda olduğu gibi bundan sonra tamamen Cortex Microcontroller Software Interface Standard (CMSIS) kütüphanesini kullanacağım ve register seviyesinde anlatımlar yapacağım. Onun için temel C bilgisinin eksiksiz olması gerekiyor. Ben burada C anlatmayacağım internette çok fazla kaynak var gerekli keywordleri sıralıyorum bunlar benim öncelikli olarak aklıma gelenler.

  • bitwise operators
  • bit manipulation techniques
  • accessing memory-mapped registers
  • pointers and casting
  • structures, bitfields, unions
  • const and volatile type qualifiers
  • compiler optimization

Gerekli C bilginizin olduğunu varsayarak devam ediyorum. Aslında bu konu ileri sayılabilecek bir konu genelde ilk derslerde GPIO kullanımı anlatılmaktadır. Fakat ben içeride nelerin döndüğünü anlamak adına çalıştığınız işlemcinin hangi frekansta çalıştığını bilmenin önemli olduğunu düşünüyorum. Bu konuyu anlarsak ileride timer birimlerini pwm, capture/compare kullanımını daha iyi anlamış oluruz. Yazının sonunda işlemcimizin bütün clock ayarlarına hakim olarak istediğimiz frekansta çalıştıracağız ve Systick dediğimiz özel bir timer ile delay fonksiyonu yazacağız.

Stm32 de clock ile ilgili ayarlamaların yapıldığı çevre birimi Reset and Clock Control (RCC) dir. Bu çevre biriminin ilgili registerlarına belirli sayılar yazarak clock ayarlarını yapacağız. Öncelikle bir clock sinyalinin oluşabilmesi için bir clock üreticisine ihtiyaç vardır bu dahili veya harici osilatörler ile yapılmaktadır. Benim kullandığım kartta(STM32F407VG) 16Mhz hızında çalışan dahili bir osilatör ve external olarak 8Mhz hızında çalışan kristal bulunmaktadır. Sizin çalıştığınız kartlarda bunlar farklılık gösterebilir ama hesaplamalar buna göre devam edecektir. Bu frekans değerlerini yazılımda tuttuğumuz değişkenler HSI(High Speed Internal) ve HSE(High Speed External) dir. Kullandığım kart maksimum 168Mhz hızına kadar çıkabilmektedir fakat kullandığımız osilatörlerin hızı daha düşük burada işin içine PLL(Phase Locked Loop) girmektedir. Bu sayede base clock frekansımızı belirli sabit sayılar ile çarpıp bölerek istediğimi clock hattına istediğimiz frekansta çalıştırmız oluruz. Bu anlattığım yapıyı reference manual dökümanında Clock Tree başlığında şematiğini bulabilirsiniz fakat biraz fazla detaylı onun için ST firmasının CubeMx yazılımında ki şematiği kullanarak ilerleyeceğim.

Yukarıda ki şema genel olarak clock hatlarının nasıl bağlandığını göstermektedir. Burada öncelikli olarak System Clock Mux ile gösterilen kısmı inceleyelim. Burada Sysclk olarak 3 farklı kaynak bulunmaktadır.

  1. HSI sabit 16Mhz de çalışmaktadır.
  2. HSE seçilerek sabit 8Mhz de çalıştırılabilir
  3. PLLCLK seçeneği ise PLL kullanılarak maksimum 168Mhz e çıkabilir.

Maksimum hızda çalıştıracağımızı varsayarak PLLCLK kaynağını seçmeliyiz. Daha sonra PLL’in kaynağının neresi olacağını seçmek için ise PLL Source Mux dan HSI den mi yoksa HSE den mi besleyeceğimizi seçmemiz gerekiyor. Son olarak Sysclk maksimum hızda çalıştıracağız fakat AHB, APB1, APB2 bus hatlarını da her birinin prescaler değeri ile oynayarak farklı frekanslarda çalıştıracağız. Peki PLL değerlerini neye göre seçeceğiz. Clock hesaplama için bir formülümüz var.

SystemCoreClock = ((INPUT_CLOCK (HSE_OR_HSI_IN_HZ) / PLL_M) * PLL_N) / PLL_P

Bu formülü kendi değerlerimize uygularsak şöyle bir şey olacaktır. 168000000 = (8000000/8)*336/2

  • PLL değerleri: PLL_M = 8, PLL_N = 336, PLL_P = 2
  • Bus Prescaler: AHB Prescaler = 1, APB1 Prescaler = 4, APB2 Prescaler = 2

Sonuç olarak bütün ayarlamaları yaptıktan sonra şöyle bir çıktı olması bekleniyor.

  • SYSCLK: 168MHz
  • AHB: 168Mhz
  • APB1: 42Mhz
  • APB2: 84Mhz

Yukarıda ki şemada görülen bütün seçme işlemlerinin aslında RCC çevre biriminin birer registerından kontrol edildiğini unutmayalım. Ben burada öncelikli ihtiyaç duyduğumuz ayarlamaları anlattım bazı çevre birimleri farklı ayarlara ihtiyaç duymaktadır. Gerekli teorik bilgiyi öğrendiğimize göre artık kod yazmaya geçebiliriz. Kodun tamamına bu adresten erişebilirsiniz.

Reference manualin 81. sayfasında Cpu hızını nasıl artıracağımıza dair adımlar bulunmaktadır.

Yukarıda görüldüğü gibi öncelikle flash ayarlarının yapılması gerekmektedir. Şimdilik bu adımı sadece yazıp geçeceğim daha sonra flash ile ilgili bölümü anlatırken detaylarına gireceğim.

Donanımsal olarak HSE kullanacağımız için öncelikle bunu aktif etmemiz gerekiyor. Default olarak HSI aktif gelmektedir. Bunu yapabilmek için RCC_CR(Control Register) ile işlem yapmamız gerekiyor.

Sayfa 224 de RCC_CR registerı ile ilgili bitler görülmektedir. Registerın reset value değerine bakarsak HSION = 1 olarak görülmektedir. Yani başlangıçta HSI aktif haldedir. Registerın 16. biti ise bizim ilgilendiğimiz HSE değerini aktif hale getirmektedir. Eğer bu bit e 1 değerini yazarsak donanımsal olarak HSE aktif hale gelecektir. Bunun için aşağıda ki kodu yazmamız gerekiyor. Bir alt satırda ise aynı registerın 17. biti olan HSERDY bitini kontrol ettiriyoruz. Eğer bu değer 1 değil ise devam etmiyor kod.

Yukarıda ki kodda eşitliğin sol tarafı bir pointerın işaret ettiği adrestir sağ taraf ise oraya yazılacak değerdir. Ben burada RCC_CR_HSEON adında önceden stm32f4xx.h dosyasında tanımlanmış bir değeri kullanıyorum. Bu sayede adres değerlerini sürekli kontrol etmiyorum ve daha hızlı kod yazmış oluyorum. Ama bu değerin arka tarafta bir header dosyasından geldiğini unutmamak önemlidir. Bu değer header dosyasında #define ile tanımlanmıştır ve değeri “((uint32_t)0x00010000)” budur. Yani 16. bit e 1 yazılmış hali 😉

HSE yi aktif hale getirdikten sonra yukarıda ki şemada ki pll source mux değerlerini belirlememiz gerekiyor.

Yukarıda ki gibi programa PLL i bi HSE kaynağından kullanacağımızı belirtmemiz gerekiyor.

Burada ikinci bir register olan RCC_PLLCFGR kullanıyoruz.

Sayfa 226 da bu registıra ait bilgiler bulunmaktadır. 22. bitin PLLSRC olduğuna dikkat edelim peki buraya ne yazacağız ?

Görüldüğü gibi eğer buraya 1 yazar isek PLL i HSE den kullanabileceğiz.

Artık PLL i nereden kullanacağımız biliyoruz ve gerekli PLL değerlerini atamamız gerekiyor. Bunun için tekrardan RCC_PLLCFGR registerına bakmamız gerekiyor.

0 ile 6. bit e kadar PLLM değerini yazmamız gerekiyor yukarıda ki kod ile PLL_M=4 yapmış oluyoruz.

16 ile 17. bitler PLLP değerini yazmamız gerekiyor. Üst taraftaki kod ile PLL_P=2 yapmış olduk.

6 ile 15. bitler PLLN değerini yazmamız gerekiyor. Yukarıda ki kod ile PLL_N=168 atamış olduk. Bu sayede bütün PLL değerlerini ayarladık. Şimdi sıra clock buslarının prescaler değerlerini belirlemede.

Yukarıda ki kod ile RCC_CFGR registerında ilgili alanları set ederek prescaler değerlerini vermiş olduk.

PLL ve prescaler değerlerini verdikten sonra PLL i aktif hale getireceğiz.

RCC_CR registerını kullanarak PLLON yapıyoruz ve hazır olana kadar bekliyoruz.

Son olarak da sistem clock muxa kaynağımızın PLLCLK olduğunu belirtmemiz gerekiyor.

Bu işlemleri yaptıktan sonra sistem clock update fonksiyonunu çağırarak yaptığımız değişikliklere göre SystemCoreClok değişkenini güncelliyoruz.

Tüm bu yaptığımız işlemleri bir fonksiyon haline getirerek main dosyanızdan çağırabilirsiniz. Bu şekilde cpu maksimmum frekansta çalışmaya başlayacaktır. Şimdi gerçekten bu frekansta çalışıyormuyuz onu kontrol edelim bunun için Systick kullanarak bir delay fonksiyonu yazalım.

Systikc aslında özel bir timer diyebiliriz cpu frekansında çalışmaktadır. İleride anlatacağımız RTOS sistemlerinin temelini oluşturmaktadır. Biz bu birimi kullanarak delay fonksiyonu oluşturalım.

Her zaman yaptığımız gibi ilgili registerları bulmamız gerekiyor. Fakat bu sefer bir farklılık olacak ve ilgili registerı reference manual de bulamayacağız çünkü bu birim işlemcinin üzerinde bulunmaktadır ve ARM firması tarafından tasarlanmıştır. Yani ST firmasının dökümanında bulamayız onun yerine Cortex M4 Core dökümanına bakmamız gerekiyor. İlgili dökümanın 249. sayfasında Systick ile ilgili registerlar bulunmaktadır.

Yukarıda fonksiyonumuzu hazırladık. Burada LOAD registerına 168000 değerini yükledik yani timer o değere kadar sayacak ve biz cpu nun 168mhz de çalıştığını bildiğimiz için bu değere kadar 1 kere saymasının 1milisaniye süreceğini biliyoruz. Daha sonra VAL değerini temizledik ve Systick enable ettik. Fonksiyonumuz bit integer deger alıyor biz eğer bu fonksiyon içerisinde timerı n kadar tekrar ettirirsek n milisaniye beklemiş oluruz. For döngüsü içerisinde timer flagini kontrol ettiriyoruz. Fonksiyondan çıkarken de Systick disable ediyoruz.

Bu fonksiyonu main içerisinden DelayMs(1000) şeklinde çağırırsak 1 saniyelik bekleme oluşturmuş oluruz. Son olarak main fonksiyonumuz şu şekilde olmaktadır.

Yukarıda ki kod ile PD15 pini (Mavi LED) saniye de bir yanıp sönmesi gerekmektedir.

Bu değeri gerçekten kontrol etmek için benim elimde olan yazılımsal bir logic analizör kullanacağım. Aşağıda görüldüğü gibi çıkış pinimiz 1 saniye boyunca high 1 saniye boyunca low olmaktadır.

Bu yazımı da burada noktalıyorum seriyi devam ettirmek istiyorum sağlıcakla kalın.

2 Replies to “Arm 2: Stm32 RCC register ve clock ayarları”

  1. Soner Boztaş says: Reply

    Çok verimli ve açıklayıcı bilgiler olmuş, ellerinize emeklerinize sağlık.

    1. Teşekkürler Soner bey iyi okumalar.

Leave a Reply