जब ATmega328 पर 64 के क्लॉक प्रिस्क्रेलर पर चल रहा है, तो मेरी एक टाइमर निष्पादन में एक विशेष समय पर अज्ञात कारणों से गति करता है।
मैं Tme5940 द्वारा आवश्यक क्लॉकिंग उत्पन्न करने के लिए ATmega328 पर दो टाइमर का उपयोग कर रहा हूं (नीचे क्यों देखें, यह सवाल के लिए सार है)। TIMER0
फास्ट पीडब्लूएम का उपयोग करके एक घड़ी संकेत उत्पन्न करता है OC0B
और इसे निम्नानुसार सेट किया जाता है:
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
प्रत्येक 256 TIMER0
चक्रों में एक खाली पल्स उत्पन्न करने के लिए एक डेटा लाइन को ट्विंडल करता है और इसे निम्नानुसार सेट किया जाता है:
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
अतिप्रवाह (प्रत्येक 256 चक्र) पर एक ISR कहता है। ISR मैन्युअल रूप से एक खाली पल्स, और एक लैचिंग पल्स उत्पन्न करता है यदि आवश्यक हो:
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()
उपरोक्त कोड में देरी सिर्फ तर्क विश्लेषक का पता लगाने पर नाड़ी अधिक पारदर्शी बनाने के लिए है। यहां बताया गया है कि main()
फंक्शन में लूप कैसा दिखता है: कुछ सीरियल डेटा भेजें, ISR के लैचिंग की देखभाल करने के लिए प्रतीक्षा करें, और फिर इसे फिर से करें:
for (;;) {
if (!fLatch) {
sendSerial();
fLatch = 1;
_delay_ms(1);
}
nop();
}
sendSerial()
कुछ एसपीआई भेजता है ( संक्षिप्तता के लिए pastebin पर कोड )। मेरा मुद्दा यह है कि sendSerial()
पूरा होने के बाद , fLatch
कम (संसाधित) होने की प्रतीक्षा करते समय क्लॉकिंग टाइमर की गति बढ़ जाती है। यहाँ लॉजिक एनालाइज़र ट्रेस है (मैंने उन क्षेत्रों को काट दिया है जहाँ ग्राफिक को छोटा बनाने के लिए एक ही संकेत जारी रहता है):
बाईं ओर, चैनल 0 और 1 एसपीआई डेटा के टेल एंड को दिखाते हैं। इसके अलावा बाईं ओर, चैनल 4 पर, आप एक खाली पल्स देख सकते हैं। चैनल 2 पर क्लॉकिंग पल्स चग्स के रूप में अपेक्षित। जहां छवि में अंतराल है, उसके आसपास ही दिनचर्या के अंदर fLatch
सेट किया 1
गया main()
है। और जल्द ही बाद TIMER0
में एक कारक के बारे में 4 से गति करता है। आखिरकार, खाली पल्स और लैचिंग पल्स का प्रदर्शन किया जाता है (चैनल 3 और 4, छवि का सही तीसरा), और अब क्लॉकिंग पल्स अपनी नियमित आवृत्ति, और सीरियल डेटा को फिर से शुरू करता है। पुनः भेजा गया। मैंने delay_ms(1);
लाइन को अंदर लेने की कोशिश की main()
, लेकिन वही परिणाम प्राप्त हुए हैं। क्या चल रहा है? मुझे ध्यान देना चाहिए कि ATmega को 20Mhz क्रिस्टल से बंद करके रखा गया है और फिर निम्न कोड का उपयोग करके 64x तक धीमा कर दिया गया है:
CLKPR = 1<<CLKPCE;
CLKPR = (0<<CLKPS3)|(1<<CLKPS2)|(1<<CLKPS1)|(0<<CLKPS0);
यह किसके लिए है: मैं TLC5940 एलईडी ड्राइवर को नियंत्रित करने के साथ प्रयोग कर रहा हूं : इन चिप्स को एक बाहरी घड़ी और क्लॉकिंग चक्र के अंत में रीसेट की आवश्यकता होती है।
sendSerial()
एसपीआई के माध्यम से डेटा भेजने वाला मेरा कोड है: यह TCCR
(टाइमर नियंत्रण) रजिस्टर को नहीं छूता है ।