ATmega328'de AVR zamanlayıcı hızı


9

ATmega328'de 64 saat önbelleğinde çalışırken, zamanlayıcılarımdan biri yürütmedeki belirli bir zamanda bilinmeyen nedenlerle hızlanır.

Ben ihtiyaç duyduğu zamanlamanın üretmek için ATMega328 iki zamanlayıcılar kullanıyorum TLC5940 (neden üzerinde aşağıya bakınız; bu soruya önemsizdir). TIMER0Hızlı PWM açık kullanarak bir saat sinyali üretir OC0Bve aşağıdaki gibi ayarlanır:

TCCR0A = 0
    |(0<<COM0A1)    // Bits 7:6 – COM0A1:0: Compare Match Output A Mode
    |(0<<COM0A0)    // 
    |(1<<COM0B1)    // Bits 5:4 – COM0B1:0: Compare Match Output B Mode
    |(0<<COM0B0)
    |(1<<WGM01)     // Bits 1:0 – WGM01:0: Waveform Generation Mode
    |(1<<WGM00)
    ;
TCCR0B = 0
    |(0<<FOC0A)     // Force Output Compare A
    |(0<<FOC0B)     // Force Output Compare B
    |(1<<WGM02)     // Bit 3 – WGM02: Waveform Generation Mode
    |(0<<CS02)      // Bits 2:0 – CS02:0: Clock Select
    |(1<<CS01)
    |(0<<CS00)      // 010 = clock/8
    ;
OCR0A = 8;
OCR0B = 4;
TIMSK0 = 0;

TIMER2her 256 TIMER0döngüde bir körleme darbesi oluşturmak için bir veri hattını döndürür ve aşağıdaki gibi ayarlanır:

ASSR = 0;
TCCR2A = 0
    |(0<<COM2A1)    // Bits 7:6 – COM0A1:0: Compare Match Output A Mode
    |(0<<COM2A0)    // 
    |(0<<COM2B1)    // Bits 5:4 – COM0B1:0: Compare Match Output B Mode
    |(0<<COM2B0)
    |(0<<WGM21)     // Bits 1:0 – WGM01:0: Waveform Generation Mode
    |(0<<WGM20)
    ;
TCCR2B = 0
    |(0<<FOC2A)     // Force Output Compare A
    |(0<<FOC2B)     // Force Output Compare B
    |(0<<WGM22)     // Bit 3 – WGM02: Waveform Generation Mode
    |(1<<CS22)      // Bits 2:0 – CS02:0: Clock Select
    |(0<<CS21)
    |(0<<CS20)      // 100 = 64
    ;
OCR2A = 255;
OCR2B = 255;
TIMSK2 = 0
    |(1<<TOIE2);    // Timer/Counter0 Overflow Interrupt Enable

TIMER2taşma durumunda bir ISR çağırır (her 256 döngüde bir). ISR manuel olarak bir körleme darbesi ve gerekirse bir kilitleme darbesi üretir:

volatile uint8_t fLatch;

ISR(TIMER2_OVF_vect) {
    if (fLatch) {
        fLatch = 0;
        TLC5940_XLAT_PORT |=  (1<<TLC5940_XLAT_BIT);        // XLAT -> high
        for (int i=0;i<10;i++)
            nop();
        TLC5940_XLAT_PORT &= ~(1<<TLC5940_XLAT_BIT);        // XLAT -> high
    }
    // Blank
    TLC5940_BLANK_PORT |= (1<<TLC5940_BLANK_BIT);
    for (int i=0;i<10;i++)
        nop();
    TLC5940_BLANK_PORT &= ~(1<<TLC5940_BLANK_BIT);
}

nop()Yukarıdaki kod gecikme sadece mantık analizörü izi üzerindeki darbe daha belirgin hale getirmektir. İşlevdeki döngü main()şöyle görünür: bazı seri veriler gönderin, ISR'nin mandallama ile ilgilenmesini bekleyin ve ardından tekrar yapın:

for (;;) {
    if (!fLatch) {
        sendSerial();
        fLatch = 1;
        _delay_ms(1);
    }
    nop();
}

sendSerial()bazı SPI gönderileri yapar ( kısaca uğruna pastebin kodu ). Benim sorunum sendSerial()tamamlandıktan sonra , fLatchdüşük (işlenmiş) olarak ayarlanmasını beklerken saat zamanlayıcı hızlanır. İşte mantık analizörü izi (Aynı sinyalin grafiği küçültmeye devam ettiği alanları kestim):

resim açıklamasını buraya girin

Sol tarafta, 0 ve 1 kanalları gönderilen SPI verilerinin kuyruk ucunu gösterir. Ayrıca solda, kanal 4'te bir körleme darbesi görebilirsiniz. Kanal 2'de saatli darbe, beklendiği gibi çekilir. Görüntüdeki boşluğun fLatchtam 1ortasında, main()rutinin içine ayarlanır . Ve kısa bir süre sonra TIMER0yaklaşık 4 kat hızlanır. Sonunda, körleme darbesi ve mandallama darbesi gerçekleştirilir (kanallar 3 ve 4, görüntünün sağ üçte biri) ve şimdi saat vurma darbesi normal frekansına geri döner ve seri veriler bir daha yolla. delay_ms(1);Çizgiyi çıkarmayı denedim main(), ancak aynı sonuçlar elde edildi. Neler oluyor? ATmega'nın 20Mhz kristalinden zamanlanmış olduğunu ve daha sonra aşağıdaki kodu kullanarak 64x yavaşladığını not etmeliyim:

CLKPR = 1<<CLKPCE;
CLKPR = (0<<CLKPS3)|(1<<CLKPS2)|(1<<CLKPS1)|(0<<CLKPS0);

Ne için: TLC5940 LED sürücüsünü kontrol etmeyi deniyorum : bu yongalar, harici bir saat artı saat çevriminin sonunda bir sıfırlama gerektirir.


Bir hata ayıklayıcı varsa, zamanlayıcı çok hızlı olduğunda kodunuzu durdurmayı deneyin ve o zamanlayıcının yapılandırma kaydını tekrar okuyun. Yanlış değere sahip olanı bulduğunuzda, bu kayıt değişikliğinde bir kesme noktası tetikleyin ve kodunuzun hangi bölümünün yanlış performans gösterdiğini görün. Sorunun, kullanabileceğiniz harici bir kütüphanede bulunduğunu ve gecikme gibi dahili öğeler için bu zamanlayıcıyı kullandığını tahmin ediyorum.
Blup1980

İki sorun: a) JTAG programcım yok, bu yüzden çipte hata ayıklama yolum yok b) Yukarıda gösterilen kurulumdan sonra zamanlayıcı kayıt değerini asla değiştirmem, bu nedenle zamanlayıcı kayıt değerlerini beklemiyorum aslında değişir. Bu saf mı?
angelatlarge

1
Aslında kullandığınız bir kütüphane UART ayarlarını değiştirebilir. Bir sendSerial () işlevi kullandığınızı görüyorum. Kodunuzun bir parçası mı yoksa harici bir kütüphane mi? Ayarları değiştiren siz değil, çağrılan kitaplığın içindeki bir kod parçası olabilir. Konfigürasyon parametrelerini çıkarmak için seri portunuzu kullanmanızı ve neyin değiştiğini anlamaya çalışmanızı öneririm. Ayrıca, kullanılmış kitaplıkların kaynağına da (varsa) bakabilir ve bu zamanlayıcıyı da kullanmadığından emin olabilirsiniz.
Blup1980

1
@ Blup1980'in denemeye değer başka bir şey önerdiği dışında, saat çizgisiyle garip bir şey yapmadığından emin olmak için TLC5940'ı kaldırmaktır.
PeterJ

@ Blup1980 UART'ın alaka düzeyini gördüğümden emin değilim: USART for SPI, sadece "normal" SPI tesisleri kullanmıyorum. sendSerial()SPI aracılığıyla veri gönderen kodum: TCCR(zamanlayıcı kontrolü) kayıtlarına dokunmaz .
angelatlarge

Yanıtlar:


1

Hızlı bir hata ayıklama için, aynı şeyi TLC5940 için Arduino Kütüphanesi'ni kullanarak yapmaya çalışıyorum ve hızlı olup olmadığını görüyorum. Kütüphane ile çalışıyorsa, kaynağını kontrol edebilir ve kendinizinkiyle karşılaştırabilirsiniz. AVR'yi bildiğiniz için Arduino kaynağını kolayca yerel AVR'ye dönüştürmelisiniz.

Derlenmiş Arduino çizimlerini AVR'ye nasıl yükleyeceğinizi bilmiyorsanız: Çiziminizi derlediğinizde, bir hex dosyası oluşturur (ayarlarda ayrıntılı modu açarak dosyanın tam yerini görebilirsiniz). Bu hex'i en sevdiğiniz programcı ile AVR'nize yükleyebilirsiniz.

Umarım yardımcı olur

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.