Tiny AVR 1 Serisi- CCL

 CCL pinlere, olay sistemine veya diğer çevre birimlerine bağlanabilen programlanabilen mantık birimidir. İşlemciden bağımsız çalışır.

CCL iki adet dizi arama tablosu LUT içerir. LUT üç giriş ve bunlara bağlı programlı bir çıkış bulundurur.

LUT için bağlı girişlerin olasılıkları ve karşılık gelen TRUTH bu şekildedir. LUT için girişler INSEL biti ile ayarlanır. Bu ayarlamayla G/Ç pinler seçilebilir. Olay sistemi ile bağlanabilir. FEEDBACK ile bir LUT çıkışı diğeri için giriş olabilir. Zamanlayıcılar gibi diğer çevre birimlerine bağlanabilir.

CCL üç girişin bağlı olduğu ve AND kapısı olarak çalışmasını istediğimiz zaman TRUTH=0B 1000 0000 olmalıdır. Aynı şekilde OR için TRUTH=0B 1111 1110 olur. Bu şekilde istenen çıkış ayarlanabilir. Ayrıca istenirse girişler maskelenebilir ve iki giriş olarak kullanılabilir. Bütün bunları yapmak için ilgili registerler:

CTRLA RUNSTDBY ile uyku modunda çalışması ayarlanırken ENABLE ile CCL çalıştırılır. CCL içindeki registerler ENABLE "1" olduğunda yazmaya karşı korumalıdır. Değişiklik yapmak için "0" olmalıdır.

SEQCTRL

LUT çıkışları sıralı bir bloğa bağlanır. İçinde flip flop ve latch içerir. 


LUTCTRLA

LUTCTRLA ile ilgili LUT için ayarlamalar yapılır. Buradaki ENABLE o LUT için geçerlidir. OUTEN LUTx çıkışını açar. 

FILTSEL girişe uygulanan filtre seçimi yapılır. CLKSRC ile sistem saati veya giriş ikiye bağlanacak harici saat seçimi yapılır. EDGEGET ile yükselen kenarda bir darbe oluşturur.

LUTCTRLB, LUTCTRLC



Aşağıdaki tabloda belirtilenler arasından giriş seçimi yapılır. INSEL0 IN0, INSEL1 IN1 ve INSEL2 IN2. Bu tablolarda SPI ve USART girişleri aynı değildir.

Uygulama

İlk olarak basit bir uygulama yaparak nasıl çalıştığını öğrenmeye çalıştım. Üç adet giriş ve bu girişleri AND kapısı olarak ayarlı CCL birimine bağladım. Bu girişlerin durumuna göre çıkış olarak bağlı bir LED var.

/*
 * attiny1614_ccl_and.c
 *
 * Created: 29.03.2024 11:13:24
 * Author : haluk
 */ 

#include <avr/io.h>
int main(void){
  PORTC.DIRSET=PIN3_bm|PIN4_bm|PIN5_bm;// lUT1 girişleri
  CCL.TRUTH1=0x80;// LUT table: and için truth(7) biti "1" diğerleri "0"
  CCL.LUT1CTRLB|=CCL_INSEL0_IO_gc|CCL_INSEL1_IO_gc;//LUT 1 pinleri bağlandı
  CCL.LUT1CTRLC|=CCL_INSEL2_IO_gc;//LUT 1 pinleri bağlandı
  CCL.LUT1CTRLA|=CCL_ENABLE_bm|CCL_OUTEN_bm;//LUT1 çıkışı ve LUT1 açıldı  
  CCL.CTRLA|=CCL_ENABLE_bm;//ccl açıldı   
    while (1) 
    {
    }
}
Microchip uygulama örneklerinde gördüğüm bir uygulamayı kullandığım MCU ya göre değiştirdiğim bir örnek. Manchester kodu uygulaması. Bu konuyla ilgili bilgiyi internette bulabilirsiniz.
/*
 * attiny1614_manchester.c
 *
 * Created: 29.03.2024 14:39:03
 * Author : haluk
 */ 
#include <avr/io.h>
#include "tiny1_uart.h"
#include "tiny1_spi_master.h"
#include <util/delay.h>

int main(void){
  CPU_CCP=CCP_IOREG_gc;
  CLKCTRL_MCLKCTRLB=CLKCTRL_PDIV_10X_gc|CLKCTRL_PEN_bm;//f_cpu 2MHz    
  uart_basla(19200);
  spi_basla();  
  CCL.TRUTH1=0x09;//IEEE 802.3 LUT table sck ve mosi XOR  
  //CCL.TRUTH1=0x06;//G. E. Thomas
  CCL.LUT1CTRLB=CCL_INSEL0_SPI0_gc|CCL_INSEL1_SPI0_gc;//spi mosi ve spi sck lut1 girişi yapıldı
  CCL.LUT1CTRLC=CCL_INSEL2_MASK_gc;//giriş maskelendi
  CCL.LUT1CTRLA=CCL_OUTEN_bm|CCL_FILTSEL_SYNCH_gc|CCL_ENABLE_bm;//LUT1 çıkış açık filtre açık
  CCL.CTRLA=CCL_ENABLE_bm;  
    while (1)   {
    if (uart_gelen()){//UART ile gelen bir veri spi ile gönderilirken LUT1 (PA7) manchester çıkışı
      spi_data(uart_oku());
      _delay_us(50);
    }
    }
}
Lojik analizörde manchester ayarları.
Lojik analizörde UART,SPI ve Manchester çıkışlarının durumu.

Tiny AVR 1 Serisi- ADC

 Birçok modelde iki adet olan ADC birimi bu seride de 10 bit çözünürlüğe sahip. Eskilerle tüm özellikleri aynı değil. Olay sistemi dışında sonuçları belirli aralıklarla sınırlayabildiğimiz çerçeve modu var.

ADC


ADC birimine analog girişler (AINx) ve dahili girişler bağlanabilir. Referans voltajı VDD, VREFA ve INT REF seçilebilir. ADC biriminde ölçümün nasıl yapacağı örnekleme sayısı, gecikmesi gibi ayarlamalar yapılabilir. Sonuçların toplanarak verilmesi gibi seçenekler sunar. Bu ayarlamaları yaptığımız registerleri açıklayarak ilerlemek daha doğru olacak.

CTRLA registerinde bulunan ENABLE ile ADC birimi çalışmaya başlar. Bu bit "0" ise birim enerji harcamaz ve sayacı sıfırlanır. FREERUN ile ilk ölçüm komutu sonrası sürekli olarak çevrim devam eder. RESSEL ile birimin 10-8 bit arası çözünürlük seçimi yapılır.
CTRLB registerinde bulunan SAMPNUM ile sonuçların toplanarak yazılması sağlanabilir.
CTRLC de bulunan PRESC sistem saatinin bölme oranını ayarlayarak çalışma frekansını belirleriz. ADC birimi bu seride 50kHz ile 1.5MHz arası frekansta çalışmaya uygundur. REFSEL ile referans kaynak seçimi yapılır. SAMPCAP referans voltajına bağlı olarak seçim yapılır. 1V üstünde "1" yapılmalıdır.
CTRLD INTDLY ile ADC birimi başlatılırken oluşacak gecikme ayarlanır. ASDV ile ardışık çevrimler arası gecikme değerleri değişken olacak şekilde ayarların. Bu bit "1" yapıldığında SAMDLY birer birer artar. Bu artış 0x00 ile 0x0F arasında sürekli devam eder. Bu sabit frekanslı örneklemeyi önleyerek sinyalden rastgele örnekler almaya yarar. SAMPDLY ile örnekleme arasındaki gecikme belirlenir.
Bir ADC çevrimini gösteren bu şemada başlatma ve örnekleme gecikmesini görebiliriz.

CTRLE ile eski serilerde olmayan bir özellik ayarlanabilir. WINCM ile tablodaki seçenekler arasından seçim yapılır. Çerçeve modu diyeceğim bu seçenekte belirlediğimiz değerlerle çevrim sonu bulunan sonuç karşılaştırılır. Tabloda bulanan seçeneklere göre yapılan bu karşılaştırma sonunda WCMP kesme bayağı "1" olur. Bu seçenekler şu şekilde olabilir.  Sonuç belirlenen çerçeve değerlerinin arasında/dışında veya alt değerin altında, üst değerin üstünde şeklindedir.
SAMPCTRL ile örnek uzunluğunu belirleyebiliriz. SAMPDLY kısmındaki çevrim şemasında görüldüğü şekilde işler. SAMDLY ve SAMPLEN birlikte kullanımı sonunda ön görülemeyen gecikmeler olabilirmiş. Bu konuda bir hata bildirimi var fakat ben denediğimde sorun yaşamadım.
MUXPOS ADC biriminin ölçüm yapılacak olan girişi seçtiğimiz registerdir. Tablodan ADCx birimine bağlı pin seçilir.
COMMAND registerinde bulunan STCONV biti "1" yapıldığında ADC çevrimi başlar.
EVCTRL ADC birimi olay sistemine bağlı olarak çevrime başlayabilir. Bunun için kullanıcı olarak tanımlanmalı ve STARTEI "1" yapılmalıdır.
INTCTRL ve INTFLAGS iki register aynı isimde iki bit bulundurur. Kesmeleri açmak ve oluşan kesmeleri kontrol etmek için bu registerler kullanılır. Kesme bayrağı için INTFLAGS registerinde ilgili bit "1" yapılır.
Bunların dışında sonuç RES, çerçeve modu eşik değerleri WINLT,WINHT bulunur. Çevrim sonucu için RES okunur. Yukarıda bahsettiğim çerçeve modu için gerekli değerler WINLT,WINHT ye yazılır.

CALIB ADC biriminin çalışma frekansı 1.5MHz üstünde ise DUTYCYC "0" yapılmalıdır. Varsayılan değer "1" dir.

Uygulama

İlk olarak ADC birimini kullanmak için gerekli yapılandırmayı yapıyorum. Yapacağım iki uygulamadan biri her çevrimde yoklama yöntemiyle çevrimin bitmesini bekleyecek. Diğerinde ise ölçmeye olay sisteminden buton sinyali ile başlayacak ve kesme sonunda okuma yapılacak.

/*
 * attiny1614_adc.c
 *
 * Created: 27.03.2024 16:57:28
 * Author : haluk
 */ 
#include <avr/io.h>
#include <stdio.h>
#include "tiny1_uart.h"
#include <util/delay.h>
uint16_t adc=0;
char sonuc[10];

int main(void){
  CPU_CCP=CCP_IOREG_gc;
  CLKCTRL_MCLKCTRLB=(0<<CLKCTRL_PEN_bp);//20mhz
  uart_basla(Bd115200);
  ADC0.CTRLA|=ADC_RESSEL_10BIT_gc;// adc 10 bit
  ADC0.CTRLB|=ADC_SAMPNUM_ACC1_gc;//örnekleme sayısı 2
  ADC0.CTRLC|=ADC_REFSEL_VDDREF_gc|ADC_PRESC_DIV32_gc|ADC_SAMPCAP_bm;//referans vdd, prescaler 32 625kHz
  ADC0.CTRLD|=ADC_INITDLY_DLY16_gc|ADC_SAMPDLY_3_bm;//başlatma gecikmesi 16, örnekleme gecikmesi 3
  ADC0.SAMPCTRL|=ADC_SAMPLEN_2_bm;//örnekleme uzunluğu 2
  ADC0.MUXPOS|=ADC_MUXPOS_AIN1_gc;//adc pin seçimi adco ain1 pa1
  //ADC0.CALIB|=ADC_DUTYCYC_DUTY50_gc;//1.5MHz üstünde
  ADC0.CTRLA|=ADC_ENABLE_bm;//adc0 enable
  ADC0.COMMAND=ADC_STCONV_bm;//ölçüm başlatma  boş ölçüm 
    while (1)  {   
    ADC0.COMMAND=ADC_STCONV_bm;//ölçüm başlatma
    while (!(ADC0.INTFLAGS&ADC_RESRDY_bm));//sonuç bayrağı bekle
    ADC0.INTFLAGS|=ADC_RESRDY_bm;//bayrak temizlendi
    adc=ADC0.RES;//sonuç okundu
    sprintf(sonuc,"adc: %u\n",adc);
    uart_dizi(sonuc);
    _delay_ms(100);
    }
}
Event sistem PB7 ile çevrim başlatma
/*
 * attiny1614_adc_int.c
 *
 * Created: 27.03.2024 17:25:12
 * Author : haluk
 */ 

#include <avr/io.h>
#include <avr/interrupt.h>
#include <stdio.h>
#include "tiny1_uart.h"
#include <util/delay.h>
volatile uint16_t adc=0;
volatile uint8_t flag=0;
char sonuc[10];

ISR(ADC0_RESRDY_vect){
  ADC0.INTFLAGS|=ADC_RESRDY_bm;//bayrak temizlendi
  adc=ADC0.RES;  
  flag=1;
}
int main(void){
  CPU_CCP=CCP_IOREG_gc;
  CLKCTRL_MCLKCTRLB=(0<<CLKCTRL_PEN_bp);//20mhz
  uart_basla(Bd115200);
  PORTB.DIRCLR=PIN7_bm;//pb7 giriş butona basıldıkça okuma yapar
  PORTB.PIN7CTRL=PORT_PULLUPEN_bm;//pull up
  EVSYS.ASYNCCH1=EVSYS_ASYNCCH1_PORTB_PIN7_gc;
  EVSYS.ASYNCUSER1=EVSYS_ASYNCUSER1_ASYNCCH1_gc;  
  ADC0.CTRLA|=ADC_RESSEL_10BIT_gc;// adc 10 bit
  ADC0.CTRLB|=ADC_SAMPNUM_ACC1_gc;//örnekleme sayısı 2
  ADC0.CTRLC|=ADC_REFSEL_VDDREF_gc|ADC_PRESC_DIV32_gc|ADC_SAMPCAP_bm;//referans vdd, prescaler 32 625kHz
  ADC0.CTRLD|=ADC_INITDLY_DLY16_gc|ADC_SAMPDLY_3_bm;//başlatma gecikmesi 16, örnekleme gecikmesi 3
  ADC0.SAMPCTRL|=ADC_SAMPLEN_2_bm;//örnekleme uzunluğu 2
  ADC0.MUXPOS|=ADC_MUXPOS_AIN1_gc;//adc pin seçimi adco ain1 pa1
  ADC0.EVCTRL=ADC_STARTEI_bm;//event sistem başlatma  
  ADC0.INTCTRL|=ADC_RESRDY_bm;
  ADC0.CTRLA|=ADC_ENABLE_bm;//adc0 enable 
  sei();    
    while (1)  {
    if(flag==1){
      flag=0;
      sprintf(sonuc,"adc: %u\n",adc);
      uart_dizi(sonuc);     
    }   
    }
}


Tiny AVR 1 Serisi- TCD 12 Bit Zamanlayıcı

 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ş.