Trong một ứng dụng thời gian thực - trên ARM Cortex M3 (tương tự STM32F101), tôi cần thăm dò một chút về thanh ghi ngoại vi bên trong cho đến khi nó bằng 0, càng chặt càng tốt. Tôi sử dụng dải bit để truy cập bit thích hợp. Mã C (đang hoạt động) là
while (*(volatile uint32_t*)kMyBit != 0);
Mã đó được sao chép trong RAM thực thi trên chip. Sau khi tối ưu hóa thủ công², vòng bỏ phiếu giảm xuống như sau, tôi đã hẹn giờ đến 6 chu kỳ:
0x00600200 681A LDR r2,[r3,#0x00]
0x00600202 2A00 CMP r2,#0x00
0x00600204 D1FC BNE 0x00600200
Làm thế nào sự không chắc chắn bỏ phiếu có thể được hạ xuống? Một vòng lặp 5 chu kỳ sẽ phù hợp với mục tiêu của tôi: lấy mẫu đó càng gần càng tốt với 15,5 chu kỳ sau khi nó về không.
Thông số kỹ thuật của tôi gọi đáng tin cậy để phát hiện xung thấp ít nhất 6,5 chu kỳ xung nhịp CPU; đáng tin cậy phân loại nó là ngắn nếu nó kéo dài dưới 12,5 chu kỳ; và đáng tin cậy phân loại nó miễn là nếu nó kéo dài hơn 18,5 chu kỳ. Các xung không có mối quan hệ pha xác định với xung nhịp CPU, đây là tham chiếu thời gian chính xác duy nhất của tôi. Điều đó đòi hỏi một vòng bỏ phiếu tối đa 5 đồng hồ. Trên thực tế, tôi đang mô phỏng mã chạy trên CPU 8 bit hàng chục năm tuổi có thể thăm dò với chu kỳ 5 xung nhịp và những gì đã trở thành thông số kỹ thuật.
Tôi đã cố gắng bù căn chỉnh mã bằng cách chèn NOP trước vòng lặp, trong nhiều biến thể tôi đã thử, nhưng không bao giờ quan sát thấy sự thay đổi.
Tôi đã cố gắng đảo ngược CMP và LDR, nhưng vẫn nhận được 6 chu kỳ:
0x00600200 681A LDR r2,[r3,#0x00]
; we loop here
0x00600202 2A00 CMP r2,#0x00
0x00600204 681A LDR r2,[r3,#0x00]
0x00600206 D1FC BNE 0x00600202
Đây là 8 chu kỳ
0x00600200 681A LDR r2,[r3,#0x00]
0x00600202 681A LDR r2,[r3,#0x00]
0x00600204 2A00 CMP r2,#0x00
0x00600206 D1FB BNE 0x00600200
Nhưng đây là 9 chu kỳ:
0x00600200 681A LDR r2,[r3,#0x00]
0x00600202 2A00 CMP r2,#0x00
0x00600204 681A LDR r2,[r3,#0x00]
0x00600206 D1FB BNE 0x00600200
Đo thời gian bit thấp bao nhiêu, trong bối cảnh không xảy ra gián đoạn.
² Mã do trình biên dịch ban đầu tạo ra đã sử dụng r12 làm thanh ghi đích và đã thêm 4 byte mã vào vòng lặp, tốn 1 chu kỳ.
Các số đã cho có được với trình giả lập STIce thời gian thực được cho là chính xác theo chu kỳ và tính năng kích hoạt trình giả lập của nó khi đọc tại địa chỉ của người đăng ký. Trước đây tôi đã thử bộ đếm "Trạng thái" với điểm dừng trong vòng lặp, nhưng kết quả phụ thuộc vào vị trí của điểm dừng. Một bước thậm chí còn tệ hơn: nó luôn đưa ra 4 chu kỳ cho LDR, khi đó ít nhất là xuống 3.
gcc -Os -mcpu=cortex-m3
?
ldr
/ cbz reg, end_of_loop
cho những cái bên trong, và vẫn là cmp
/ bnz
ở phía dưới. Nhưng điều đó sẽ cung cấp cho bạn một khoảng thời gian bỏ phiếu không đồng nhất, ví dụ 1 trong mỗi 8 cuộc thăm dò, trong trường hợp có vấn đề.