Tiny AVR 1 Serisi -TCA 16 Bit Zamanlayıcı

 Toplamda dört adet zamanlayıcı bulunmaktadır. Bir birinden farklı özelliklerde olan bu birimlerden ilki tip A ve 16 bit olan TCA0 birimidir.

TCA


  Üç farklı karşılaştırma seçeneği dört kesme kaynağı vardır. Sayaç değeri ve karşılaştırma değerleri için sürekli kontrol edilen bir bellek bulunmaktadır. Sayaç için sistem saati prescaler ile belirlenir. sayaç (CNT) 0 ile 0xFFFF arasında olabileceği gibi eskilerde olmayan bir özellikle üst sınıra (PER) farklı bir değer girebiliriz. TC1 de seçilen moda göre TOP değeri değiştirme şansı yoktu. Bunun için birden fazla mod arasından istenen frekans için 8-10 bit mod seçiyorduk. Bu birimde TOP değeri PER ile istediğimiz aralıkta seçerek PWM frekansını belirleyebiliyoruz. TCA da ayrıca PWM çıkışı çoğaltmak için 16 bit registerlerin ayrıldığı bir split mod var. Üç olan çıkış pini bu sayede artırılabilir. Ayrıca PORTMUX ile belirli pinler arası değişiklik yapılabilir.

Modlar ve bu modların güncellenme durumlarıyla üst değerleri gösteren tablo.

Normal Mod

Yön biti (DIR) ile belirlenen yöne doğru CNT artar/azalır. DIR "0" ise CNT artar "1" ise azalır. Yöne bağlı olarak alt (BOTTOM) veya üst (TOP) değerde CNT sıfırlanır. CNT ye istenirse bir değer girilebilir. Bu değere göre artmaya/azalmaya devam eder. Burada TOP değer PER ile belirlenen değerdir.

TCA da Double Buffering olarak isimlendirilen bir özellik bulunur. CMP veya PER kayıtlarında bir değişiklik yapıldığında bu bellek kayıtlarında bulunan bayrak aktif olur. Bu özellik kullanılmadığında PER kaydı öncekinden düşük bir değer getirildiğinde CNT artmaya devem eder MAX değere kadar ulaşır. Sonraki artışta yeni PER kaydıyla eşleşince normal çalışmasına devam eder. Bu özellik kullanılırsa. Bir önceki değerde sıfırlanır sonraki artışta yeni değer ile devam eder.

CNT seçilen yöne göre değişirken karşılaştırma kaydıyla (CMP) sürekli karşılaştırılır. Eşleşme durumunda kesme oluşur. Ayrıca PER kaydına veya BOTTOM değere ulaşınca taşma OVF kesmesi de oluşturulabilir. 

Frekans Modu

CNT belirlenen yöne göre değişirken CMP0 ile eşleştiğinde sıfırlanır. Burada TOP değer CMP0 dır.


Çıkış için WO0 (PA0) pini veya tersi durum içn WO1 kullanılır.. Çıkış frekansı için CMP0 değerini bulmak için gereken formül şemanın altında yazılı. Buradan CMP0=(Fclk/FRQ2N)-1 şeklinde bulunur. Bir değişiklik yapılmamışsa MCU çalışma frekansı 3.333.333 dür. Prescaler 2 olarak seçip 50Hz çıkış istersek:
CMP0=(3333333/50Hz/2pre/2)-1 ve CMP0=16665 olur.

Tek Eğimli PWM

Bu mod ile PWM çıkışı elde edilir. Bunun için WO0,WO1 WO2 pinleri kullanılır. PORTMUX ile belirli pinler arasında değişiklik yapılabilir. CNT alttan PER değerine doğru artarken CMPx ile eşleşme durumuna göre çıkış darbeleri oluşur.

CMPx değeri alt ile aynı olursa sürekli "0" ve üst PER ile aynı veya büyük olursa sürekli "1"çıkış verir. PER değeri PWM frekansını, CMPx değeri Duty oranını belirler. Frekans için yukarıdaki örneğe benzer işlem yapılır. 1KHz ve 1 Prescaler değeri için olması gereken CMPx=(3333333/1000Hz/1pre)-1=3332 bulunur.

Çift Eğimli PWM

Bu modda CNT PER değerine kadar artar eşleşme sonrası alt değere kadar azalır ve döngü devam eder. CMPx değeriyle eşleşme olduğunda çıkış verir.

Bu modda maksimum frekans diğerinin yarısı kadar olacaktır. PWM çıkışı alabilmek için ilgili pinlerin çıkış olarak ayarlanması gerekir. TCA biriminde aktif edilen bir pinin çıkış değeri geçersiz olur. Yönetim TCA birimine geçer. Pinlerin çıkış durumunu tersleme şansı vardır. Bir önceki konuda bahsettiğim INVEN biti kullanılır.
Buraya kadar olan bölüm normal/single olarak adlandırılıyor.

Split Mod

16 bit CNT ve CMPx kayıtları 8 bit olarak ayrılır ve PWM çıkış sayısı artırılır. Split modda registerler değişiklik gösterir. Sayaç yukarıdan aşağıya doğru sayar. Sadece tek eğimli PWMmod kullanılabilir.  Bu çalışma moduna geçmek için CTRLD registeri SPLITM biti "1" yapılır.

CNT registeri CNTH ve CNTL isminde iki farklı sayaç olarak çalışır. Yukarıdan aşağı doğru azalır ve alta ulaşınca underflow kesmeleri oluşur. Bu sayaçların üst değeri PERH ve PERL ile belirlenir. Bu değerleri belirlerken önce PERL sonra PERH yazılmalıdır. PER değeri olarak girmek de mümkün
Bu modda kesme isimleri de farklıdır. Normal ve Split mod kesmeler arası farklılıklar:


TCA zamanlayıcı ayarlama  öncesi isteniyorsa split mod seçilmelidir. Sonra sırasıyla CTRLB,C,D ve varsa INTRCTRL registerleri ayarlanmalıdır. En son CTRLA enable biti ve prescaler belirlenmelidir. TCA biriminde reset, restart ve update gibi komutlar var. Update normalde CNT değerinin (TOP,BOTTOM,CMP) eşleşmesiyle oluşan etkiyi yapar. Restart CNT ve CMP değerlerini sıfırlayarak tekrar başlatır. Reset tüm register değerlerini başlangıç değerine getirir.


Uygulama

Satırların yanına gerekli yorumları ekledim.
Single Mod Tek eğimli PWM:
/*
 * attiny1614_tca.c
 *
 * Created: 13.03.2024 11:39:03
 * Author : haluk
 */ 
#define F_CPU 3333333
#include <avr/io.h>
#include <util/delay.h>

int main(void){
  PORTB.DIRSET=PIN0_bm|PIN1_bm;//WO0 ve WO1 pini çıkış yapıldı
  TCA0.SINGLE.PER=3332;//1KHZ için gereken top değer
  TCA0.SINGLE.CTRLB|=TCA_SINGLE_WGMODE_SINGLESLOPE_gc|TCA_SINGLE_CMP0EN_bm|TCA_SINGLE_CMP1EN_bm;// tek eğimli PWM, CMP0 ve CMP1 açıldı
  TCA0.SINGLE.CTRLC|=TCA_SINGLE_CMP0OV_bm|TCA_SINGLE_CMP1OV_bm;//CMP çıkışları açıldı
  TCA0.SINGLE.CTRLA|=TCA_SINGLE_CLKSEL_DIV1_gc|TCA_SINGLE_ENABLE_bm;//prescaler değeri ve sayaç başlatıldı  
    while (1){    
    for (uint16_t i=0;i<3332;i++){
      TCA0.SINGLE.CMP0=3332-i;
      TCA0.SINGLE.CMP1=i;      
      _delay_ms(1);
    }
    for (uint16_t i=3332;i>0;i--){
      TCA0.SINGLE.CMP0=3332-i;
      TCA0.SINGLE.CMP1=i;
      _delay_ms(1);
    }    
    }
}
Split Mod PWM (4 çıkış farklı frekanslarda):
/*
 * attiny1614_tca_split.c
 *
 * Created: 16.03.2024 16:27:12
 * Author : haluk
 */ 

#define F_CPU 3333333
#include <avr/io.h>
#include <util/delay.h>

int main(void){
  PORTB.DIRSET=PIN0_bm|PIN1_bm;//WO0 ve WO1 çıkış yapıldı
  PORTA.DIRSET=PIN3_bm|PIN4_bm;//WO3 ve WO4 çıkış yapıldı
  TCA0.SPLIT.LPER=103;//2KHz WO0 ve 1 PWM freq
  TCA0.SPLIT.HPER=207;//1KHz WO3 ve 4 PWM freq  
  TCA0.SPLIT.CTRLD=TCA_SPLIT_SPLITM_bm;// split
  TCA0.SPLIT.CTRLB|=TCA_SPLIT_LCMP0EN_bm|TCA_SPLIT_LCMP1EN_bm|TCA_SPLIT_HCMP0EN_bm|TCA_SPLIT_HCMP1EN_bm;//WO0,1,3,4 karşılaştırma açıldı
  TCA0.SPLIT.CTRLC|=TCA_SPLIT_LCMP0OV_bm|TCA_SPLIT_LCMP1OV_bm|TCA_SPLIT_HCMP0OV_bm|TCA_SPLIT_HCMP1OV_bm;//WO0,1,3,4 çıkış olarak açıldı
  TCA0.SPLIT.CTRLA|=TCA_SPLIT_CLKSEL_DIV16_gc|TCA_SINGLE_ENABLE_bm;//prescaler değeri ve sayaç başlatıldı
  
    while (1){
    for (uint16_t i=0;i<207;i++){
      TCA0.SPLIT.LCMP0=103-i/2;
      TCA0.SPLIT.LCMP1=i/2;
      TCA0.SPLIT.HCMP0=207-i;
      TCA0.SPLIT.HCMP1=i;
      
      _delay_ms(1);
    }
    for (uint16_t i=207;i>0;i--){
      TCA0.SPLIT.LCMP0=103-i/2;
      TCA0.SPLIT.LCMP1=i/2;
      TCA0.SPLIT.HCMP0=207-i;
      TCA0.SPLIT.HCMP1=i;
      _delay_ms(1);
    }    
    }
}
Kesmelerin Ayarlanması ve Kullanımı:
/*
 * attiny1614_tca_int.c
 *
 * Created: 15.03.2024 20:50:23
 * Author : haluk
 */ 
#define F_CPU 3333333 // 20MHz / 6(default prescale) 
#include <avr/io.h>
#include <util/delay.h>
#include "tiny1_uart.h"

ISR(TCA0_OVF_vect){  //overflow taşma kesmesi yön değişirse underflow
  uart_gonder('C');
  TCA0.SINGLE.INTFLAGS=0x01;// Bayraklar otomatik temizlenmiyor
}
ISR(TCA0_CMP0_vect){//CMP0 eşleşme kesmesi  
  uart_gonder('B');
  TCA0.SINGLE.INTFLAGS=0x10;// Bayraklar otomatik temizlenmiyor
}
ISR(TCA0_CMP1_vect){//CMP1 eşleşme kesmesi    
  uart_gonder('A');
  TCA0.SINGLE.INTFLAGS=0x20;// Bayraklar otomatik temizlenmiyor
}
int main(void){
  
  uart_basla(Bd115200);
  cli();
  TCA0.SINGLE.PER=52082;// Top değer 3333333/64=52083 1 sn sonunda sayaç değeri
  TCA0.SINGLE.CMP0=30000;//rastgele değer
  TCA0.SINGLE.CMP1=25000;////rastgele değer
  //FREQ modda top değer CMP0 olduğundan OVF kesmesi CMP0 ile birlikt gerçekleşir.
  //Normal Çift veya tek eğimli modda kullanılabilir.
  TCA0.SINGLE.CTRLB|=TCA_SINGLE_WGMODE_SINGLESLOPE_gc;//tek eğimli mod
  TCA0.SINGLE.INTCTRL|=TCA_SINGLE_OVF_bm|TCA_SINGLE_CMP0_bm|TCA_SINGLE_CMP1_bm;//kesmeler açıldı
  TCA0.SINGLE.CTRLA|=TCA_SINGLE_CLKSEL_DIV64_gc|TCA_SINGLE_ENABLE_bm;//prescaler değeri ve sayaç başlatıldı
  TCA0.SINGLE.INTFLAGS|=0xFF;// Bayraklar otomatik temizlenmiyor
  sei();      
   
    while (1)   {
    }
}















Hiç yorum yok:

Yorum Gönder