Câu trả lời của @ Abbeyatcu là khá toàn diện. Một điều nữa cần lưu ý là CPU có thể chạy trong trạng thái chờ (chu kỳ CPU bị đình trệ) khi truy cập I / O, bao gồm bộ nhớ chương trình và dữ liệu.
Ví dụ: chúng tôi đang sử dụng TI F28335 DSP; Một số vùng của RAM là trạng thái chờ 0 cho bộ nhớ chương trình và dữ liệu, vì vậy khi bạn thực thi mã trong RAM, nó sẽ chạy ở 1 chu kỳ trên mỗi lệnh (ngoại trừ các hướng dẫn mất hơn 1 chu kỳ). Tuy nhiên, khi bạn thực thi mã từ bộ nhớ FLASH (EEPROM tích hợp, nhiều hay ít), nó không thể chạy ở mức đầy đủ 150 MHz và chậm hơn nhiều lần.
Đối với mã ngắt tốc độ cao, bạn phải tìm hiểu một số điều.
Đầu tiên, trở nên rất quen thuộc với trình biên dịch của bạn. Nếu trình biên dịch thực hiện công việc tốt, thì nó không nên chậm hơn nhiều so với lắp ráp bằng tay cho hầu hết mọi thứ. (trong đó "chậm hơn nhiều": hệ số 2 sẽ ổn với tôi; hệ số 10 sẽ không được chấp nhận) Bạn cần tìm hiểu cách (và khi nào) sử dụng cờ tối ưu hóa trình biên dịch, và thỉnh thoảng bạn nên xem tại đầu ra của trình biên dịch để xem nó hoạt động như thế nào.
Một số điều khác mà bạn có thể có trình biên dịch làm để tăng tốc mã:
sử dụng các hàm nội tuyến (không thể nhớ nếu C hỗ trợ điều này hoặc nếu đó chỉ là C ++ - ism), cho cả các chức năng nhỏ và cho các chức năng sẽ chỉ được thực hiện một hoặc hai lần. Nhược điểm là các hàm nội tuyến khó gỡ lỗi, đặc biệt là nếu tối ưu hóa trình biên dịch được bật. Nhưng chúng giúp bạn tiết kiệm các chuỗi cuộc gọi / trả lại không cần thiết, đặc biệt nếu sự trừu tượng hóa "chức năng" là dành cho mục đích thiết kế khái niệm hơn là thực thi mã.
Xem hướng dẫn sử dụng của trình biên dịch của bạn để xem nó có các hàm nội tại hay không - đây là các hàm dựng sẵn phụ thuộc vào trình biên dịch ánh xạ trực tiếp đến các hướng dẫn lắp ráp của bộ xử lý; một số bộ xử lý có hướng dẫn lắp ráp thực hiện những việc hữu ích như đảo ngược min / max / bit và bạn có thể tiết kiệm thời gian thực hiện.
Nếu bạn đang thực hiện tính toán số, hãy đảm bảo rằng bạn không gọi các hàm thư viện toán học một cách không cần thiết. Chúng tôi đã có một trường hợp mã giống như y = (y+1) % 4
một bộ đếm có chu kỳ 4, hy vọng trình biên dịch sẽ thực hiện modulo 4 dưới dạng bit-AND. Thay vào đó, nó được gọi là thư viện toán học. Vì vậy, chúng tôi thay thế y = (y+1) & 3
để làm những gì chúng tôi muốn.
Làm quen với trang hack bit-twiddling . Tôi đảm bảo bạn sẽ sử dụng ít nhất một trong số này thường xuyên.
Bạn cũng nên sử dụng (các) thiết bị ngoại vi hẹn giờ của CPU để đo thời gian thực thi mã - hầu hết chúng đều có bộ hẹn giờ / bộ đếm có thể được đặt để chạy ở tần số xung nhịp CPU. Chụp một bản sao của bộ đếm ở đầu và cuối mã quan trọng của bạn và bạn có thể thấy nó mất bao lâu. Nếu bạn không thể làm điều đó, một cách khác là hạ thấp chân đầu ra ở đầu mã của bạn và nâng nó ở cuối và xem đầu ra này trên máy hiện sóng để xác định thời gian thực hiện. Có sự đánh đổi cho từng cách tiếp cận: bộ đếm thời gian / bộ đếm bên trong linh hoạt hơn (bạn có thể mất nhiều thời gian) nhưng khó lấy thông tin hơn, trong khi cài đặt / xóa mã pin đầu ra có thể nhìn thấy ngay lập tức trên một phạm vi và bạn có thể thu thập số liệu thống kê, nhưng thật khó để phân biệt nhiều sự kiện.
Cuối cùng, có một kỹ năng rất quan trọng đi kèm với kinh nghiệm - cả chung và với các kết hợp bộ xử lý / trình biên dịch cụ thể: biết khi nào và khi nào không tối ưu hóa . Nói chung, câu trả lời là không tối ưu hóa. Trích dẫn Donald Knuth được đăng thường xuyên trên StackOverflow (thường chỉ là phần cuối cùng):
Chúng ta nên quên đi những hiệu quả nhỏ, nói về 97% thời gian: tối ưu hóa sớm là gốc rễ của mọi tội lỗi
Nhưng bạn đang ở trong một tình huống mà bạn biết rằng bạn phải thực hiện một số loại tối ưu hóa, vì vậy đã đến lúc cắn viên đạn và tối ưu hóa (hoặc có bộ xử lý nhanh hơn hoặc cả hai). Đừng KHÔNG viết toàn bộ ISR của bạn trong lắp ráp. Đó gần như là một thảm họa được bảo đảm - nếu bạn làm điều đó, trong vòng vài tháng hoặc thậm chí vài tuần bạn sẽ quên đi những phần bạn đã làm và tại sao, và mã có thể rất dễ vỡ và khó thay đổi. Có khả năng là một phần mã của bạn, tuy nhiên, đó là những ứng cử viên tốt để lắp ráp.
Dấu hiệu cho thấy các phần của mã của bạn rất phù hợp để mã hóa lắp ráp:
- các chức năng có chứa thường xuyên, được xác định rõ các thói quen nhỏ không có khả năng thay đổi
- các chức năng có thể sử dụng các hướng dẫn lắp ráp cụ thể (min / max / right shift / etc)
- các hàm được gọi nhiều lần (giúp bạn nhân số nhân: nếu bạn tiết kiệm 0,5usec cho mỗi cuộc gọi và được gọi 10 lần, điều đó giúp bạn tiết kiệm 5 usec, điều này rất có ý nghĩa trong trường hợp của bạn)
Tìm hiểu các quy ước gọi hàm của trình biên dịch của bạn (ví dụ: nơi nó đặt các đối số trong các thanh ghi và đăng ký nào nó lưu / khôi phục) để bạn có thể viết các thói quen lắp ráp có thể gọi được C.
Trong dự án hiện tại của tôi, chúng tôi có một cơ sở mã khá lớn với mã quan trọng phải chạy trong ngắt 10kHz (100usec - nghe có quen không?) Và không có nhiều chức năng được viết trong cụm. Những thứ đó là, những thứ như tính toán CRC, hàng đợi phần mềm, bù / tăng bù ADC.
Chúc may mắn!