Merhaba,

Bugünkü yazımızda Timer ve Counterlara giriş yapacağız.  Geliştirme kitlerini alırken bazı önemli özelliklerine göz atmak büyük bir önem arz etmektedir. Uygulamanız için ihtiyacınız olan ADC (Analog-to-Digital) çözünürlüğü, Timer sayısı, kristal frekansı, pin sayısı vb. bu özelliklerin başında gelmektedir. Bu yazı bağlamında elimde bulunan STM32F767ZI geliştirme kitine Timer kanalları açısından inceleyecek olursak genel amaçlı 10 adet timer olduğunu görebiliriz. ARM programlamaya giriş yazımızda bahsettiğimiz Mbed platformunun web sitesinde kullandığınız kitin fiziksel görünümü ve sahip olduğu özellikler listelenmektedir. Google’ a kitinizin adını yazarak çıkan sonuçlardan mbed web sitesi olanı seçerek bilgilere ulaşabiliriz. Örneğin STM32F767ZI nezdinde mbed kendi internet sitesinde Şekil 1’ de gösterilen özelliklerin bilgisini paylaşmaktadır.

Şekil 1: Mbed internet sitesinde STM32F767′ ye ait özellikler

Görüldüğü üzere tüm çevresel birimler sayılarıyla ve özellikleriyle kullanıcıları bilgilendirmek üzere paylaşılmıştır. Tabi sizler bu bilgilere datasheetler üzerinden de ulaşabilirsiniz. Ancak pratik olmak açısından bu yolu da sizlerle paylaşmak istedik… Bir timer, birden fazla kanala sahip olup her bir kanalı birbirinden farklı konfigürasyonlar yapılabilecek şekilde tasarlanmıştır. Bu konfigürasyonlar “PWM Generation”, “Output Compare”, “Forced Output”, “Input Capture” gibi metotlardan oluşmaktadır. Sırası geldikçe her birine ait uygulamaları gerçekleyeceğiz. İlk etapta timerları yakından tanımak adına gerekli konfigürasyonları yapıp kendimize ait bir gecikme (delay) yaratarak başlayacağız.

Uygulamamızı gerçeklemeden önce bazı kavramları ve mantıklarını tanıtmamızda yarar olacaktır. Önceki uygulamalarımızda hatırlarsanız RCC (Reset and Clock Control) modülüyle herhangi bir işlem yapmamıştık. Bu nedenle CubeMX ara yüzünde “Clock Configurations” sekmesiyle herhangi bir işimiz olmamıştı. RCC’ nin aktifleştirilmesi mikroişlemcinizin ulaşabileceği en yüksek hızda çalışmasını sağlayan bir external osilatörü devreye alır. Bu noktada biraz fikir yürütecek olursak, internal (iç) kaynağa ek olarak bir dış kaynak kullanmış olacağız. Böylelikle mikroişlemci el verdiği sürece dilediğimiz hıza çıkmamız mümkün olacaktır. Söz konusu timerlar olduğunda ise, timerlar osilastör tarafından sağlanan “clock source” ‘u (clock kaynağını) kullanmaktadırlar. Bununla birlikte timerlar olay tabanlı (event based) çalıştıklarından dolayı belirli bir periyotta bir olayın gerçekleşmesi durumu ortaya çıkmaktadır. Peki event ya da olay olarak adlandırdığımız şey de nedir? Cevabımız çoktan öğrenmiş olduğunuz ya da zaten bildiğiniz kesmeler! Evet, timer kanalı üzerinden kesmeler (interrupt) kullanılarak ve belirli periyotlarda bu kesmeleri (event, olay) yaratarak örneğin bir kare dalga ya da delay gibi fonksiyonları üretebilmek mümkündür.  

Birçok farklı timer registerı bulunmaktadır. Bunlardan bazıları status, control, CCR (Capture Compare), ARR (Auto Reload Register), OCR (Output Compare Register), RCR (Repetition Counter Register) olarak sıralanır. Registerlarımızdan bahsettiğimize göre şu soruyu sorma vaktinin geldiğini düşünüyoruz: timer clock source’ u nasıl kullanmaktadır ve kesme süresini (frekansını/periyodunu) nasıl ayarlayabiliriz?

Şekil 2: Clock Confiuration ekranı ve default kristal hızı (16 MHz., max 216 MHz.)

Şekil 2’ de görülebildiği üzere Clock Configuration sekmesinde güncel çalışma frekansının 16 MHz. yani 16000000 Hz ’dir.  Bu frekansı doğrudan kullanmak ise olan biteni insan gözüyle gözlemlemek açısından oldukça fazladır. Timer geliştiricilere bu frekansı bölmek kaydıyla kendisini besleme imkanını sunmaktadır. Timer’ı bölen katsayıya “prescaler” adı verilir. Timer kendi içinde bir sayıcı olarak nitelendirilebileceği için sizlerin belirleyeceği bir limite kadar merdiven gibi artarak, azalarak ya da önce artıp sonra azalarak sayan bir yapıdır. Sayıcı limiti ise 16 bitlik bir register olan ARR (Auto Reload Register) tarafından tutulur. Dolayısıyla dilerseniz program içerisinde, dilerseniz CubeMX üzerinde bu üst limiti belirleyebilme olanağına sahibiz. Eventlerin birer kesme olduklarından behsetmiştik. Bu durumda şu ana kadar öğrendiklerimizi birleştirirsek eventlerin overflow durumunda gerçekleştiğini söyleyebiliriz. Bu da demek oluyor ki ARR üst limitine ulaştığında kesme fonksiyonu devreye girecek ve kesme içerisinde yazdığımız komutlar çalışacaktır. ARR, prescaler ve clock source dikkate alındığında timer kesmesinin gerçekleşme sıklığını ifade eden bir eşitlik ortaya atabiliriz. Böylece bu eşitliği kullanarak prescaler ve overflow (üst aşım) bilgilerini tutan registerlara yazılması gereken değerleri belirleyebiliriz.

Timer_kesme_frekansı = Clock_Frekansı / ( (ARR + 1) * (Psc + 1) )

Bu ifadeyi bir örnekle pekiştirelim. Çalışma frekansımızın 16 Mhz olduğu durumu ele alacak olursak ve ihtiyacımız olan periyodun 1 saniye olmasını istersek Timer kesme frekansının 1 Hz. olması gerekecektir. Uygun bir değer örneği olarak prescaler değerini 1599 ve ARR değerini 9999 olarak belirlediğimizde kesme frekansının 1 Hz. olacağını görmekteyiz. Bu da t*f = 1 eşitliğinden yola çıktığımızda 1 saniyeye karşılık gelecektir.   

Bir saniye arayla led yakıp söndürmekle başlayalım. Bunun önce CubeMX üzerinde timer konfigürasyonlarını yapmamız gerekmektedir. Bu projede “System Core” sekmesi altında bulunan RCC’ yi High Speed Clock (HSE) -> Crystal/Ceramic Resonator olarak ayarlamış olsak da henüz Clock Configuration menüsünde bulunan frekans değeriyle oynamayacağız. Ancak sizler bu değerle oynayarak ihtiyacınız olan ARR ve Prescaler değerlerini bulmaya çalışabilirsiniz. Böylece uygulamayı pekiştirmek adına iyi bir deneyim yaşamış olursunuz 😊.

Şekil 3: RCC sekmesi, HSE aktivasyonu

Ardından diğer timer fonksiyonlarıyla şimdilik aklımızı karıştırmadan timers sekmesi altından TIM10’ a tıklayıp Şekil 4’ te gösterilen kofigürasyonları yapıyoruz.

Şekil 4: Timer konfigürasyonu. 1 sn arayla kesme fonksiyonu üretmek için gerekli parametreler.

Sıradaki adımımız NVIC sekmesinden TIM10’ a ait kesme fonksiyonunu aktifleştirmek olacaktır.

Şekil 5: NVIC sekmesinden Timer kesmesinin aktifleştirilmesi

Evet! Bu aşama itibariyle kod üretmeye hazırız. Gerekli proje ayarlarını Project Manager sekmesi üzerinden yaparak, KEIL tarafında olan bitene göz atmaya başlayalım. Yavaş yavaş her adımı görselleştirmek yerine artık KEIL içinde bulunan Functions sekmesini nasıl kullanacağını bildiğinize inanıyorum. “stm32fxxx_hal_tim.c” dosyası içerisindeki fonksiyonlara şu anda yazıya ara verip incelemenizi tavsiye ediyoruz. Burada bu aşamada kullanmamız gereken tek fonksiyon HAL_TIM_Base_Start_IT fonksiyonu olacaktır. Bu fonksiyon TIM_HandleTypeDef veri tipinde sadece bir parametre alır ve kullanılacak timer ve konfigürasyonlarını içeren bu yapıya ait kesme aktifleştirilmiş olacaktır (parametre htim10 şeklinde ya da daha genel haliyle htimx). Sonsuz döngünün hemen öncesinde bu fonksiyonu bir kez çağırıyoruz. Bu durumda sonsuz döngü içi boş bir şekilde aynen kalacaktır.

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_TIM1_Init();
  MX_TIM10_Init();
  /* USER CODE BEGIN 2 */
  HAL_TIM_Base_Start_IT(&htim10); //Buraya dikkat!
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
    //DO NOTHING!
  }
  /* USER CODE END 3 */

Ardından “stm32fxxx_it.c” dosyasına tıklayıp bu dosyayı açıyoruz. Genelde bu dosyanın en sonunda bulunan, aktif ettiğiniz ilgili timera ait kesme fonksiyonunu göreceksiniz.

Şekil 6: stm32fxx_it.c dosyasında bulunan timer kesme fonksiyonu

Bu aşamada 1 saniye aralıklarla yanıp sönen bir led blink uygulaması elde etmiş olduk. Uygulama linkini sizlerle paylaşmak üzere aşağıya bırakıyoruz. Bir sonraki yazımızda görüşmek üzere, hoşça kalın! 😊

https://github.com/karamelekrobotics/karamelektch_timer1

Bir Cevap Yazın