Saat berjalan pada clock prescaler 64 pada ATmega328, salah satu timer saya mempercepat untuk alasan yang tidak diketahui pada waktu tertentu dalam eksekusi.
Saya menggunakan dua timer pada ATmega328 untuk menghasilkan clocking yang dibutuhkan oleh TLC5940 (lihat di bawah tentang mengapa; ini tidak penting untuk pertanyaan). TIMER0
menghasilkan sinyal jam menggunakan Fast PWM on OC0B
dan diatur sebagai berikut:
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;
TIMER2
twiddles baris data untuk menghasilkan pulsa kosong setiap 256 TIMER0
siklus dan diatur sebagai berikut:
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
TIMER2
memanggil ISR saat overflow (setiap 256 siklus). ISR secara manual menghasilkan pulsa pengosongan, dan penguncian pulsa jika perlu:
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);
}
The nop()
keterlambatan dalam kode di atas adalah hanya untuk membuat denyut nadi lebih jelas pada jejak analisa logika. Begini tampilan loop dalam main()
fungsi: kirim beberapa data serial, tunggu ISR untuk menjaga pengunciannya, dan kemudian lakukan lagi:
for (;;) {
if (!fLatch) {
sendSerial();
fLatch = 1;
_delay_ms(1);
}
nop();
}
sendSerial()
apakah beberapa SPI mengirim ( kode pada pastebin demi singkatnya ). Masalah saya adalah bahwa setelah sendSerial()
selesai, sambil menunggu untuk fLatch
diatur ke rendah (diproses), pencatat waktu pencatat waktu mempercepat. Inilah jejak penganalisa logika (saya memotong area di mana sinyal yang sama terus membuat grafik lebih kecil):
Di sisi kiri, saluran 0 dan 1 menunjukkan ujung ekor dari data SPI yang dikirim. Juga di sebelah kiri, di saluran 4, Anda dapat melihat pulsa yang kosong. Pada saluran 2, denyut nadi clocking sepanjang seperti yang diharapkan. Tepat di sekitar celah gambar, fLatch
diatur ke 1
dalam main()
rutinitas. Dan segera setelah itu TIMER0
dipercepat sekitar faktor 4. Akhirnya, pulsa pengosongan dan penguncian pulsa dilakukan (saluran 3 dan 4, sepertiga kanan gambar), dan sekarang pulsa pencatat waktu memulai kembali frekuensi regulernya, dan data serial Kirim lagi. Saya mencoba mengambil delay_ms(1);
garis dalam main()
, tetapi hasil yang sama diperoleh. Apa yang sedang terjadi? Saya harus mencatat bahwa ATmega clock kristal 20Mhz dan kemudian melambat 64x menggunakan kode berikut:
CLKPR = 1<<CLKPCE;
CLKPR = (0<<CLKPS3)|(1<<CLKPS2)|(1<<CLKPS1)|(0<<CLKPS0);
Untuk apa ini: Saya bereksperimen dengan mengendalikan driver LED TLC5940 : chip ini membutuhkan jam eksternal plus reset pada akhir siklus clocking.
sendSerial()
adalah kode saya yang mengirim data melalui SPI: tidak menyentuh TCCR
register (pengatur waktu).