12 Bit D tipi zamanlayıcı birimi 4 farklı dalga formu ve 10 adet giriş modu bulundurur. Sistem saatinden bağımsız olarak çalışabilir. Harici bir saat kaynağına bağlanabilir.
TCD
İki farklı (WOA/WOA) çıkış ve bu çıkışları kontrol eden dört karşılaştırma (CMPx) registeri bulunur. Çıkışlar A ve B ye bağlı olarak C ve D şeklinde artabilir. Olay sistemine bağlı iki farklı girişi ve aynı zamanda olay başlatıcı olarak kullanılan iki farklı çıkışı vardır .
TCD sayaç saat kaynağı olarak iç osilatöre direk bağlı olarak çalışabildiği gibi sistem saati, harici bir kaynak ve PLL ile de çalışır. CTRLA registeri ile ayarlanan saat kaynağı bu seride PLL için rezerv yazılı olsa da açılabiliyor. PLL çarpanları için hangi rezerv register kullanılıyor bilmediğimden o ayarlamaları yapamadım. Senkron ve sayaç için prescaler yanında giriş olaylarında gecikme ayarlamak için delay prescaler bulunur. Senkron ve sayaç için istenen frekansı yakalama, çok küçük değerleri elde etme şansını artırır.
CTRLA ve diğer sabit registerlerde değişiklik yapabilmek için ENABLE biti "0" yapılmalıdır. Bunun için STATUS registeri ENRDY bitinin "1" olması beklenir. Çift bellekli registerlerde bir değişiklik yapıldığında bu değişiklik işlenmez. Bunun için yapılması gereken CTRLE registeri SYNC veya SYNCEOC bitine "1" yazmaktır. Bunu yapabilmek için STATUS CMDRDY biti "1" olmalıdır. Ayrıca CTRLC registeri AUPDATE biti "1" yapılırsa CMPBCLRH registerine yazılınca otomatik olarak döngü sonu yapılır. CMPBCLR değerinin sabit olduğu modlarda kullanılamaz. SYNC yapılan değişikliği anında geçerli kılar. SYNCEOC ise TCD döngü sonu geçerli olmasını sağlar.
Tek Rampa Modu
TCD biriminde dalga formu çıkış veren dört mod bulunur bunlardan ilki tek rampa modu.
TCD sayacı sıfırdan CMPBCLR değerine kadar artar ve sıfırlanır. Bu şekilde bir periyod tamamlanmış olur. Bu döngü sırasında CMPASET ile eşleşemede WOA "1" olur. CMPACLR eşleşesinde WOA "0" olur. CMPBSET eşleşmesinde WOB "1" olur ve CMPBCLR eşleşmesinde WOB "0" olur. A çıkışı "0" olduğu zaman DTA ve "1" olduğu zamana OTA denir. Aynı şekilde B çıkışı için de DTB ve OTB şeklinde isimlendirilir.
Bu modda çıkışların çakışması istenirse CMPBSET değeri CMPACLR veya CMPASET değerinden daha küçük bir değerde olmalıdır.
TCD periyodu hesaplamak için TCDper=(CMPBCLR+1)/TCDfreq formülü kullanılır. TCDfreq TCD saat kaynağını belirtir. Sistem saati veya başka kaynak kullanılır ve prescaler ile bölünürse çıkan sonuç yazılır. 10MHz sistem saatini kullandığımızda ve 1kHz çıkış frekansı istediğimizde çıkan değerin 12 biti geçmemesi için prescaler 4 seçtiğimizde yazmamız gereken CMPBCLR değeri: Fout=1/TCDper=TCDfreq/(CMPBCLR+1) ise CMBCLR=(TCDfreq/Fout)-1 olur. CMPBCLR=(10M/4/1000)-1=2499 olur. CMPBCLR frekansı diğer karşılaştırma değerleri oranı verir.
Çift Rampa Modu
Bu modda sayac CMPACLR değerine kadar artar sıfırlanır. Ardından CMPBCLR değerine kadar artar ve sıfırlanır. Bu şekilde bir döngü tamamlanmış olur. Sayacın bu değişikliği sırasında CMPxSET değerleriyle eşleşme sonucu çıkışlar "1"-"0" olur.
Bu modda çıkışların çakışma şansı yoktur. Bir periyod TCDper=(CMPACLR+CMPBCLR+2)/TCDfreq ile bulunur.
Dört Rampa Modu
Sayaç CMPASET değerine kadar artar sıfırlanır WOA çıkışı "1" olur. Sayaç CMPACLR değerine kadar artar sıfırlanır ve WOA çıkışı "0" olur. Sayaç CMPBSET değerine kadar artar sıfırlanır ve WOB "1" olur. Son olarak sayaç CMPBCLR değerine kadar artar WOB "0" olur ve döngü tamamlanır.
TCDper=(CMPASET+CMPACLR+CMPBSET+CMPBCLR+4)/TCDfreq
Çift Eğim modu
Bu modda sayaç CMPBCLR değerinden başlar ve sıfıra kadar azalır ve tekrar artmaya devam eder. CMPCLR değerine ulaşınca döngü tamamlanır. TCDper=(2*(CMPBCLR+1))/TCDfreq ile periyod bulunur.
Sayaç CMPBCLR değerinde aşağı sayarken CMPBSET ile eşleşince WOB "0" olurken, CMPASET değeriyle eşleşince WOA "1" olur. Yukarı çıkarken eşleşmede WOA "0" olurken WOB "1" olur. CMPASET >CMPBSET olursa çıkışlar çakışabilir.
Çift eğim modunda istenirse CTRLE registeri DISEOC biti "1" yapılarak tek döngü elde edilebilir.
TCD Girişler
TCD olay sistemine bağlı iki giriş bulunur. Bu girişlerin gerekli ayarlamaları EVCTRLx ve INPUTCTRLx registerleriyle yapılır.
A girişinde TCD döngüsünün istenen bir zamanında giriş sinyalini maskeleyen veya geciktiren bir özelliği vardır. B girişinde bu özellik bulunmaz. Onun dışında aynı yapıya sahiptir. TCD bu girişlere bağlı olarak farklı modlara sahiptir.
Bu modlar tüm dalga formu çıkış modlarıyla birlikte kullanılamaz. Bu tablo hangi giriş modunun kullanılabileceğini gösterir.
Mode 0:
Bu mod ile girişlerin çıkışlar üstünde bir etkisi yoktur. Buna rağmen girişe bağlı olarak kesme oluşabilir.
Mode 1:
Girişe bağlı olarak çıkışı durdurur. Sonraki zaman geçmeden TCD giriş sinyali olduğu sürece bekler. Sinyal kesildiğinde sonraki zamandan devam eder. Biraz daha açık ifadeyle giriş A bir sinyal aldığında çıkış A ve TCD sayaç durur. Sinyal kaybolduğunda TCD devam eder ama A nın yarım kalan OTA zamanından sonraki DTB zamanından devam eder.
Mode 2:
Giriş bağlı çıkışı durdurur TCD devam eder sonraki zamanlar gerçekleşir. Giriş sinyali devam ediyorsa ilgili girişin zamanına geldiğinde TCD durur.
Mode 3:
Girişe bağlı çıkış durur. Diğer çıkış tekrar tekrar devam eder. Diğer DTx ve OTx olmadığından devam edenin frekansı artmış olur.
Mode 4:
Girişlerden hangisinden sinyal gelirse gelsin çıkışlar durur ama TCD devam eder.
Mode 5:
Girişler çıkışları durdurur, TCD DTa ve DTB arasında devam eder.
Mode 6:
Girişler çıkışları durdurur, TCD durur ve sinyal kalkınca sonraki DTx den devam eder.
Mode 7:
İki girişde çıkışları durdurur, TCD durur ve yazılımla başlatana kadar bekler. CTRLE RESTART
Mode 8:
Açık olan çıkışa bağlı girişten gelen yükselen kenar o çıkışı durdurur. TCD sonraki DTx ile devam eder.
Mode 9:
Açık olan çıkışa bağlı girişten gelen yükselen kenar o çıkışı durdurur. TCD etkilenmez döngüye devam eder.
Mode 10:
Giriş bağlantılı çıkış açıkken çıkışı durdurur. giriş sinyali oldukça çıkış durur. TCD etkilenmez döngüye devam eder.
Dither
Saat kaynağı ile istenen frekansa tam olarak ulaşmak mümkün olmayabilir. Kesirli çıkan döngü sürelerini ile istenene frekansa ulaşabilmek için ilave döngü eklenebilir. Bunun için DITCTRL ile hangi zamana ekleneceğini ve DITVAL ile eklenecek döngü sayısını belirleyebiliriz.
TCD Sayaç
TCD sayacı sistem saatiyle birlikte çalışmadığından doğrudan okuma şansı yok. Bunu yapmak için iki yöntem var. TCD olay sistemine bağlı girişler istenirse girişe bağlı olarak yakalama etkinleştirilebilir. Bunun için EVCTRLx de bulunan ACTION "1" yazılır. Girişe bağlı yakalama olduğunda TRIGx bayrağı "1" olur. CAPTURExL ve CAPTURExH ile sayaç okunur. İstenirse bu durumda bir kesme de oluşturulabilir.
Girişe bağlı iki sinyalden ilki yükselen kenarda diğeri düşen kenarda yakalama yapacak şekilde ayarlanmış.
Bir diğer yöntem ise yazılımla okumadır. Bunun için CTRLE de bulunan SCAPTUREx "1" yapılır. Bunu yapabilmek için STATUS CMDRDY "1" olması beklenmelidir. Tekrar CMDRDY "1" olduğunda sırasıyla CAPTURExL ve CAPTURExH ile sayaç okunur.
Giriş modu 8 ile tek rampa modunda sayaç sıfırlanmış. Bu şekilde sayaç değeri de okunabilir.
TCD Çıkışları
TCD biriminde iki adet WOA, WOB ve bunlardan hangisine bağlı olacağını seçebildiğimiz WOC, WOD bulunur. Bu çıkışları açmak için FAULTCTRL registerinde bulunan CMPxEN biti "1" yazılır. Bu register yazmaya karşı korumalıdır. Daha önce bahsettiğim şekilde yazılabilir. Ayrıca bu register MCU güç kesilmesi ile tekrar başladığında sıfırlanır. Tekrar başlatmada TCDCFG sigorta ayarlarında kayıtlı değerleri alır. Sabit bir şekilde ayarlanmak istenirse bu sigorta ayarından da yapılabilir.
TCD Event Sistem
TCD olay sistemine bağlı girişleri olduğu gibi olay sisteminde olay oluşturucu olarak da kullanılabilir. CMPBCLR, CMPASET ve CMPBSET değerleriyle eşleşme olması durumunda olay oluşturucu olarak kullanılır. Ayrıca PROGEV ile zamanlanabilir olay oluşturucu olarak bağlanabilir. Girişte gecikme ile aynı yapıyı kullanır. İki aynı anda çalışmaz.
Uygulama
İlk olarak 50kHz frekansında PWM oluşturdum. TCD saat kaynağı olarak 20MHz osilatör direk bağlı yani sistem frekansı önemsiz. Hem sayaç hem senkron prescaler değeri "1" olarak aldım. PWM çıkış için dalga formu çift eğimli mod seçtim. Bu mod için istenen frekansta CMPBCLR değeri= (Ftcd/2Fpwm)-1=(((20M/1/1)/(2*50k))-1=199 olur. CMPxSET değerlerini oluşan kesme içinde değiştirerek duty cycle değiştiriyorum. Burada dikkat edilmesi gereken bu değerleri SET değerlerine yazdıktan sonra senkron komutu vermektir. Bu yapılmazsa tampona yazılan değerler işlenmez.
/*
* attiny1614_tcd.c
*
* Created: 25.03.2024 16:21:29
* Author : haluk
*/
#include <avr/io.h>
#include <avr/interrupt.h>
volatile uint8_t dutyA=0;
volatile uint8_t dutyB=0;
ISR(TCD0_OVF_vect){
TCD0.INTFLAGS|=TCD_OVF_bm;
dutyB++;
if (dutyB>199) dutyB=0;
dutyA++;
if (dutyA>199) dutyA=0;
TCD0.CMPASET=dutyA;
TCD0.CMPBSET=dutyB;
while (!(TCD0.STATUS&TCD_CMDRDY_bm));//senkron komutu olmazsa yeni değerleri işlemez. senkron komutu için cmdrdy biti 1 olmalı
TCD0.CTRLE|=TCD_SYNCEOC_bm;// sonraki döngüde tampondan bilgiler yüklenir
//TCD0.CTRLE|=TCD_SYNC_bm;//döngü sonu senkron yerine bu senkronu seçtiğimizde bellekteki değişim anınında gerçekleşir
}
int main(void){
CPU_CCP=CCP_IOREG_gc;
TCD0.FAULTCTRL=TCD_CMPAEN_bm|TCD_CMPBEN_bm;//karşılaştırma çıkış açıldı
PORTA.DIRSET=PIN5_bm|PIN4_bm;//WOA WOB çıkış ayarlandı
TCD0.CTRLA=TCD_CLKSEL_20MHZ_gc|TCD_CNTPRES_DIV1_gc|TCD_SYNCPRES_DIV1_gc;//20MHz,cnr pre 1
//PLL reserved olarak belirtilmiş sadece açılıyor ama başka ayarlamalar için hangi reserv register bilmiyorum/*TCD_CLKSEL_0_bm*/
TCD0.CTRLB|=TCD_WGMODE_DS_gc;//çift eğimli mod
TCD0.CTRLC=0;
TCD0.CMPASET=dutyA;
TCD0.CMPBSET=dutyB;
//TCD0.CMPACLR=0;// bu modda işlevsiz
TCD0.CMPBCLR=199;//50kHz PWM (CMPBCLR=(Fclk/S)/(2*Fpwm)-1=(20M/(2*50k))-1=199
TCD0.INTCTRL|=TCD_OVF_bm;//taşma kesmesi
while (!(TCD0.STATUS&TCD_ENRDY_bm));//eneble için bekleniyor
TCD0.CTRLA|=TCD_ENABLE_bm;;//tcd enable
sei();
while (1) {
}
}
Bir diğer uygulamayı giriş modlarıyla yaptım. Bu sefer sistem saatini kullandım ve 2MHz olarak ayarladım. Ayrıca sayaç prescaler 4 seçtim böylece TCD frekansı 500kHz oldu. Dalga çıkış modu tek rampa modu ve bu mod ile 200Hz çıkış frekansı ayarladım. Bunun için CMPBCLR= (Ftcd/Fpwm)-1=((2M/4)/200)-1=2499 olur. Diğer detaylar satırlarda yazıldı.
/*
* attiny1614_tcd_event.c
*
* Created: 26.03.2024 09:35:52
* Author : haluk
*/
#include <avr/io.h>
#include <avr/interrupt.h>
int main(void){
CPU_CCP=CCP_IOREG_gc;
CLKCTRL.MCLKCTRLB=(1<<CLKCTRL_PEN_bp)|CLKCTRL_PDIV_10X_gc;//2MHz
CPU_CCP=CCP_IOREG_gc;
TCD0.FAULTCTRL=TCD_CMPAEN_bm|TCD_CMPBEN_bm;//karşılaştırma çıkış açıldı
PORTB.DIRCLR=PIN7_bm;// buton
PORTB.PIN7CTRL|=PORT_PULLUPEN_bm;
PORTA.DIRSET=PIN5_bm|PIN4_bm;//WOA WOB çıkış ayarlandı
EVSYS.ASYNCCH1=EVSYS_ASYNCCH1_PORTB_PIN7_gc;//giriş olay oluşturucu buton
EVSYS.ASYNCUSER7=EVSYS_ASYNCUSER7_ASYNCCH1_gc;
TCD0.EVCTRLB|=/*TCD_EDGE_RISE_HIGH_gc|*/TCD_CFG_FILTER_gc|TCD_ACTION_CAPTURE_gc|TCD_TRIGEI_bm;
TCD0.INPUTCTRLB=TCD_INPUTMODE_EXECFAULT_gc;//mode 3
TCD0.CTRLB|=TCD_WGMODE_ONERAMP_gc;//tek rampa modu
TCD0.CMPASET=625;
TCD0.CMPACLR=1249;
TCD0.CMPBSET=1873;
TCD0.CMPBCLR=2499;
TCD0.DITCTRL=TCD_DITHERSEL_DEADTIMEAB_gc;
TCD0.DITVAL=1;
while (!(TCD0.STATUS&TCD_ENRDY_bm));//enable için hazır
TCD0.CTRLA|=TCD_CLKSEL_SYSCLK_gc|TCD_CNTPRES_DIV4_gc|TCD_SYNCPRES_DIV1_gc|TCD_ENABLE_bm;;//sistem saati,cnt pre 4,tcd enable
while (1) {
}
}
Giriş mod 3 seçili ve B girişten bir sinyal geldiğinde çıkış B durdu ama TCD devam ettiği için arka arkaya OTA-DTA oluştu. Bu nedenle 200Hz olan frekans 400Hz oldu.
Giriş mod 10 da B girişinin yükselen kenarı geldiği anda B çıkışı kesti. Normalde 1,25ms süren OTB süresi 620µs olmuş. Sinyal geldiği sürece B çıkışı durmuş ama TCD etkilenmediğinden A normal çıkışa devam etmiş.