Tăng tốc hẹn giờ AVR trên ATmega328


9

Khi chạy ở chế độ đặt trước đồng hồ 64 trên ATmega328, một trong những bộ tính giờ của tôi tăng tốc mà không rõ lý do tại một thời điểm cụ thể trong quá trình thực thi.

Tôi đang sử dụng hai bộ định thời trên ATmega328 để tạo xung nhịp cần thiết cho TLC5940 (xem bên dưới về lý do; đây là điều không quan trọng đối với câu hỏi). TIMER0tạo tín hiệu đồng hồ bằng cách sử dụng Fast PWM OC0Bvà được thiết lập như sau:

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;

TIMER2xoay một dòng dữ liệu để tạo xung trống sau mỗi 256 TIMER0chu kỳ và được thiết lập như sau:

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

TIMER2gọi ISR ​​khi tràn (cứ sau 256 chu kỳ). ISR tự tạo một xung trống và xung chốt nếu cần:

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);
}

Sự nop()chậm trễ trong đoạn mã trên chỉ là làm cho xung rõ ràng hơn trên dấu vết của bộ phân tích logic. Đây là vòng lặp trong main()hàm trông như thế nào: gửi một số dữ liệu nối tiếp, đợi ISR ​​xử lý chốt và sau đó thực hiện lại:

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

sendSerial()một số SPI gửi ( mã trên pastebin vì lý do ngắn gọn ). Vấn đề của tôi là sau khi sendSerial()hoàn thành, trong khi chờ fLatchđặt ở mức thấp (đã xử lý), bộ đếm thời gian sẽ tăng tốc. Đây là dấu vết của bộ phân tích logic (Tôi đã cắt ra các khu vực nơi tín hiệu tương tự tiếp tục làm cho đồ họa nhỏ hơn):

nhập mô tả hình ảnh ở đây

Ở phía bên trái, các kênh 0 và 1 hiển thị phần đuôi của dữ liệu SPI được gửi. Ngoài ra ở bên trái, trên kênh 4, bạn có thể thấy một xung trống. Trên kênh 2, các xung xung nhịp như mong đợi. Ngay xung quanh vị trí khoảng trống trong hình ảnh, fLatchđược đặt vào 1bên trong main()thói quen. Và ngay sau đó TIMER0tăng tốc lên khoảng 4. Gửi lại. Tôi đã cố gắng đưa ra delay_ms(1);dòng trong main(), nhưng kết quả tương tự thu được. Chuyện gì đang xảy ra vậy? Tôi nên lưu ý rằng ATmega được tắt một tinh thể 20Mhz và sau đó giảm tốc độ 64 lần bằng mã sau:

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

Cái này dùng để làm gì: Tôi đang thử nghiệm điều khiển trình điều khiển LED TLC5940 : những con chip này yêu cầu đồng hồ bên ngoài cộng với thiết lập lại ở cuối chu kỳ xung nhịp.


Nếu bạn có trình gỡ lỗi, hãy thử dừng mã của bạn khi bộ hẹn giờ quá nhanh và đọc lại thanh ghi cấu hình của bộ hẹn giờ đó. Khi bạn đã tìm thấy một giá trị sai, hãy kích hoạt điểm dừng trên thanh ghi này thay đổi và xem phần nào trong mã của bạn đang thực hiện sai. Tôi đoán rằng vấn đề nằm ở một thư viện bên ngoài mà bạn có thể sử dụng và sử dụng bộ đếm thời gian đó cho những thứ bên trong như sự chậm trễ.
Blup1980

Hai vấn đề: a) Tôi không có lập trình viên JTAG vì vậy tôi không có cách gỡ lỗi chip b) Tôi không bao giờ thay đổi giá trị thanh ghi hẹn giờ sau khi thiết lập được hiển thị ở trên, vì vậy tôi không mong đợi các giá trị đăng ký hẹn giờ thành thực sự thay đổi. Có phải là ngây thơ?
angelatlarge

1
Trên thực tế, một thư viện bạn sử dụng có thể thay đổi cài đặt UART. Tôi thấy rằng bạn sử dụng hàm sendSerial (). Nó là một phần của mã của bạn hay nó là một thư viện bên ngoài? Có thể bạn không thay đổi cài đặt mà là một đoạn mã bên trong thư viện được gọi. Tôi khuyên bạn nên sử dụng cổng nối tiếp của mình để xuất các tham số cấu hình và cố gắng tìm hiểu những gì đã thay đổi. Bạn cũng có thể xem nguồn của các thư viện đã sử dụng (nếu có) và đảm bảo rằng họ cũng không sử dụng bộ hẹn giờ đó.
Blup1980

1
Ngoài những gì @ Blup1980 đề xuất một điều khác có thể đáng thử là loại bỏ TLC5940 để đảm bảo nó không làm bất cứ điều gì tồi tệ hơn với dòng đồng hồ.
PeterJ

@ Blup1980 Tôi không chắc chắn tôi thấy sự liên quan của UART: Tôi không sử dụng USART cho SPI, chỉ là các cơ sở SPI "thông thường". sendSerial()là mã của tôi gửi dữ liệu qua SPI: nó không chạm vào các thanh ghi TCCR(điều khiển hẹn giờ).
angelatlarge

Câu trả lời:


1

Để gỡ lỗi nhanh, tôi sẽ thử làm điều tương tự bằng cách sử dụng Thư viện Arduino cho TLC5940 và xem liệu nó có nhanh hay không. Nếu nó hoạt động với thư viện, bạn có thể kiểm tra nguồn của nó và so sánh với nguồn của bạn. Vì bạn đã quen thuộc với AVR, bạn nên dễ dàng chuyển đổi nguồn Arduino sang AVR gốc.

Chỉ trong trường hợp bạn không biết cách tải các bản phác thảo Arduino đã biên dịch lên AVR: Khi bạn biên dịch bản phác thảo của mình, nó sẽ tạo một tệp hex (bạn có thể thấy vị trí chính xác của tệp bằng cách bật chế độ dài dòng trong cài đặt). Bạn có thể tải hex đó lên AVR với lập trình viên yêu thích của bạn.

Hy vọng nó giúp

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.