AVR จับเวลาเพิ่มความเร็วใน ATmega328


9

เมื่อทำงานที่ Prescaler นาฬิกา 64 ใน ATmega328 หนึ่งในตัวจับเวลาของฉันเร็วขึ้นด้วยสาเหตุที่ไม่ทราบเวลาในการดำเนินการ

ฉันใช้ตัวจับเวลาสองตัวบน ATmega328 เพื่อสร้างการตอกบัตรที่ต้องการโดยTLC5940 (ดูด้านล่างว่าทำไมเพราะนี่คือสิ่งสำคัญสำหรับคำถาม) TIMER0สร้างสัญญาณนาฬิกาโดยใช้ Fast PWM 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ทวีคูณบรรทัดข้อมูลเพื่อสร้างพัลส์ blanking ทุก ๆ 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เรียก ISR บนโอเวอร์โฟลว์ (ทุกๆ 256 รอบ) ISR สร้างพัลส์ blanking ด้วยตนเองและพัลส์ล็อคถ้าจำเป็น:

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()SPI บางอันส่ง ( โค้ดบน pastebin เพื่อความกะทัดรัด ) ปัญหาของฉันคือหลังจากsendSerial()เสร็จสิ้นในขณะที่รอfLatchการตั้งค่าต่ำ (ประมวลผล) ตัวจับเวลาการตอกบัตรจะเร็วขึ้น นี่คือการติดตามตรรกะวิเคราะห์ (ฉันตัดออกพื้นที่ที่สัญญาณเดียวกันยังคงทำให้กราฟิกมีขนาดเล็กลง):

ป้อนคำอธิบายรูปภาพที่นี่

ทางด้านซ้ายช่อง 0 และ 1 แสดงส่วนท้ายของข้อมูล SPI ที่ส่ง ทางด้านซ้ายบนช่อง 4 คุณสามารถเห็นพัลส์ blanking ในช่องที่ 2 ชีพจรสับสัญญาณนาฬิกาตามที่คาดไว้ รอบ ๆ บริเวณที่ช่องว่างของภาพfLatchตั้ง1อยู่ภายในmain()รูทีน และในไม่ช้าTIMER0ความเร็วก็เพิ่มขึ้นประมาณ 4 เท่าในที่สุดชีพจร blanking และ latching pulse จะถูกดำเนินการ (ช่อง 3 และ 4, สามในสามของภาพ) และตอนนี้ชีพจรการตอกบัตรกลับสู่ความถี่ปกติและข้อมูลอนุกรมนั้น ส่งอีกครั้ง ฉันพยายามถอดdelay_ms(1);สายmain()แต่ได้ผลลัพธ์เดียวกัน เกิดอะไรขึ้น? ฉันควรทราบว่า ATmega นั้นโอเวอร์คล็อกคริสตัล 20Mhz แล้วชะลอความเร็วลง 64x โดยใช้รหัสต่อไปนี้:

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

สิ่งนี้มีไว้สำหรับ: ฉันกำลังทดลองกับการควบคุมไดรเวอร์ LED TLC5940 : ชิปเหล่านี้ต้องใช้นาฬิกาภายนอกพร้อมการรีเซ็ตเมื่อสิ้นสุดรอบการตอกบัตร


หากคุณมีดีบักเกอร์ให้ลองหยุดโค้ดของคุณเมื่อตัวจับเวลาเร็วเกินไปและอ่านการลงทะเบียนการกำหนดค่าของตัวจับเวลานั้นอีกครั้ง เมื่อคุณพบสิ่งที่มีค่าผิดให้ทริกเกอร์เบรกพอยต์ในการเปลี่ยนแปลงการลงทะเบียนนี้และดูว่าส่วนใดของรหัสของคุณทำงานผิด ฉันเดาว่าปัญหานี้อยู่ในไลบรารีภายนอกที่คุณอาจใช้และใช้ตัวจับเวลานั้นสำหรับเนื้อหาภายในเช่นความล่าช้า
Blup1980

ปัญหาสองข้อ: ก) ฉันไม่มีโปรแกรมเมอร์ JTAG ดังนั้นฉันจึงไม่มีวิธีการดีบักชิป b) ฉันไม่เคยเปลี่ยนค่าตัวจับเวลาการจับเวลาหลังจากการตั้งค่าที่แสดงด้านบนดังนั้นฉันจึงไม่คาดหวังว่าค่าตัวจับเวลาการลงทะเบียนเป็น จริง ๆ แล้วเปลี่ยน ไร้เดียงสานั่นหรือเปล่า?
angelatlarge

1
จริงๆแล้วหนึ่งไลบรารีที่คุณใช้สามารถเปลี่ยนการตั้งค่า UART ได้ ฉันเห็นว่าคุณใช้ฟังก์ชั่น sendSerial () มันเป็นส่วนหนึ่งของรหัสของคุณหรือเป็นห้องสมุดภายนอก? อาจไม่ใช่คุณที่เปลี่ยนการตั้งค่า แต่เป็นส่วนหนึ่งของรหัสภายในไลบรารีที่เรียกว่า ฉันขอแนะนำให้คุณใช้พอร์ตอนุกรมของคุณเพื่อส่งออกพารามิเตอร์การกำหนดค่าและลองหาสิ่งที่เปลี่ยนแปลง คุณยังสามารถดูที่มาของไลบรารีที่ใช้ (ถ้ามี) และตรวจสอบให้แน่ใจว่าพวกเขาไม่ได้ใช้ตัวจับเวลานั้นด้วย
Blup1980

1
นอกเหนือจากสิ่งที่ @ Blup1980 แนะนำอีกสิ่งหนึ่งที่อาจคุ้มค่ากับการลองคือการถอด TLC5940 ออกเพื่อให้แน่ใจว่ามันไม่ได้ทำอะไรแปลก ๆ กับสายนาฬิกา
PeterJ

@ Blup1980 ฉันไม่แน่ใจว่าฉันเห็นความเกี่ยวข้องของ UART: ฉันไม่ได้ใช้ USART สำหรับ SPI เพียง "SPI" ปกติ " sendSerial()เป็นรหัสของฉันที่ส่งข้อมูลผ่าน SPI: มันไม่ได้สัมผัสTCCRการลงทะเบียน (การควบคุมการจับเวลา)
angelatlarge

คำตอบ:


1

สำหรับการดีบักอย่างรวดเร็วฉันจะพยายามทำสิ่งเดียวกันโดยใช้Arduino Library สำหรับ TLC5940และดูว่ามันจะเร็วขึ้นหรือไม่ หากใช้งานได้กับห้องสมุดคุณสามารถตรวจสอบแหล่งที่มาและเปรียบเทียบกับของคุณได้ เนื่องจากคุณคุ้นเคยกับ AVR คุณควรแปลง Arduino ต้นทางเป็น AVR ดั้งเดิมอย่างง่ายดาย

ในกรณีที่คุณไม่ทราบวิธีอัปโหลดภาพร่าง Arduino ที่รวบรวมไปยัง AVR: เมื่อคุณรวบรวมภาพร่างของคุณมันจะสร้างไฟล์ hex (คุณสามารถดูตำแหน่งที่แน่นอนของไฟล์โดยการเปิดโหมด verbose ในการตั้งค่า) คุณสามารถอัพโหลด hex ไปยัง AVR ด้วยโปรแกรมเมอร์ที่คุณชื่นชอบ

หวังว่ามันจะช่วย

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.