Làm thế nào để ngăn xếp cuộc gọi hoạt động trong một ngắt trên AVR?


8

(Cụ thể với Arduino Uno ...)

Điều gì xảy ra với ngăn xếp khi một ngắt xảy ra trên một vi điều khiển AVR và tôi gọi một hàm? Trình biên dịch nội tuyến mã? Liệu nó lưu trữ ngăn xếp ở đâu đó và sau đó thiết lập lại con trỏ ngăn xếp? Liệu nó có một ngăn xếp thứ cấp chỉ cho các ngắt?

Theo tôi hiểu, vectơ cho ngắt là một lệnh GOTO trực tiếp trong lắp ráp. Ngoài ra, tôi không nghĩ rằng vi điều khiển sẽ tự động gây rối với ngăn xếp, vì vậy nó có thể bị bỏ lại một mình. Tuy nhiên, điều đó vẫn không giải thích cách các chức năng hoạt động trong ISR.


Câu trả lời dưới đây rất hay, chỉ xin lưu ý rằng trình biên dịch không thể ngắt cuộc gọi nội tuyến vì ... Chúng là các cuộc gọi bị gián đoạn: D
Vladimir Cravero

1
@VladimirCravero Tôi có nghĩa là nội tuyến các hàm được gọi trong ngắt (nếu tôi gọi foo () trong ISR thì nó có nội tuyến không vì vậy nó không thực sự là một chức năng gọi?)
Penguin Penguin

Vì vậy, câu trả lời dưới đây không trả lời câu hỏi của bạn, hoặc nó? caveman giải thích những gì xảy ra khi một ngắt xảy ra, nhưng không phải là những gì xảy ra khi một hàm được gọi trong một bối cảnh bị gián đoạn. câu trả lời cho câu hỏi sau sẽ là: không có gì đặc biệt, hàm được gọi và đó là nó. phép thuật xảy ra khi ngắt được kích hoạt, những gì xảy ra sau (trước khi iret) chỉ là bình thường, thường không bị gián đoạn, mã.
Vladimir Cravero

@VladimirCravero có nó (gián tiếp). Tôi đã nói về cách ngăn xếp được sửa đổi cho ISR, nghĩ rằng nó phải được sửa đổi để sử dụng các chức năng ở nơi đầu tiên. Tôi sẽ đoán rằng các chức năng hoạt động theo cùng một cách chính xác sau khi ISR ​​được thiết lập.
Chim cánh cụt vô danh

tốt, bạn đã nhận nó sau đó. Sau khi nhảy đến vectơ ngắt, mọi thứ đều ổn và bạn có thể đi vòng quanh bất cứ nơi nào bạn muốn.
Vladimir Cravero

Câu trả lời:


16

AVR là một kiến ​​trúc RISC, vì vậy nó có xử lý phần cứng khá cơ bản của các ngắt. Hầu hết các bộ xử lý gây rối với ngăn xếp trong khi ngắt, mặc dù có một vài, đáng chú ý nhất là ARM và PowerPC, sử dụng các phương thức khác nhau.

Trong mọi trường hợp, đây là những gì mà AVR làm cho các ngắt:

Khi xảy ra gián đoạn, phần cứng bộ xử lý thực hiện các bước này, đây không chỉ là một GOTO đơn giản:

  1. Kết thúc hướng dẫn hiện tại.
  2. Vô hiệu hóa cờ ngắt toàn cầu.
  3. Nhấn địa chỉ của lệnh tiếp theo trên ngăn xếp.
  4. Sao chép địa chỉ trong vectơ ngắt chính xác (theo ngắt đã xảy ra) vào bộ đếm chương trình.

Bây giờ, tại thời điểm này, phần cứng đã làm tất cả những gì nó sẽ làm. Phần mềm phải được viết chính xác để không phá vỡ mọi thứ. Thông thường, các bước tiếp theo là dọc theo các dòng này.

  1. Đẩy thanh ghi trạng thái lên ngăn xếp. (Điều này phải được thực hiện trước khi nó được thay đổi).

  2. Đẩy bất kỳ thanh ghi CPU nào sẽ (hoặc có thể) thay đổi lên ngăn xếp. Những thanh ghi nào cần được lưu theo cách này được xác định bởi mô hình lập trình. Mô hình lập trình được xác định bởi trình biên dịch.

Bây giờ mã ngắt làm việc có thể được chạy. Để trả lời trường hợp trong câu hỏi gọi hàm, nó chỉ làm những gì nó luôn làm, đẩy giá trị trả về trên ngăn xếp, sau đó bật lại khi hoàn thành. Điều này không ảnh hưởng đến bất kỳ giá trị nào trước đây mà chúng tôi đã lưu trên ngăn xếp cho đến bây giờ.

  1. Chạy mã làm việc ISR.

Bây giờ chúng tôi đã hoàn thành và muốn trở về từ ngắt. Đầu tiên chúng ta phải làm sạch phần mềm.

  1. Bật các thanh ghi CPU mà chúng ta đã đẩy ở bước 6.
  2. Đưa giá trị trạng thái đã lưu trở lại vào thanh ghi trạng thái. Sau này, chúng ta phải cẩn thận không thực hiện bất kỳ lệnh nào có thể thay đổi thanh ghi trạng thái.
  3. Thực hiện hướng dẫn RTI. Phần cứng thực hiện các bước này cho hướng dẫn này:

    a. Cho phép cờ ngắt toàn cầu. (Lưu ý rằng ít nhất một lệnh phải được chạy trước khi ngắt tiếp theo sẽ được thực hiện. Điều này ngăn chặn các ngắt nặng ngăn chặn hoàn toàn công việc nền.)

    b. Bật địa chỉ trả lại đã lưu vào PC.

Bây giờ chúng tôi trở lại mã bình thường.

Lưu ý rằng có một số điểm chúng tôi phải rất cẩn thận, đặc biệt là xung quanh thanh ghi trạng thái và các thanh ghi lưu có thể được thay đổi. May mắn thay nếu bạn đang sử dụng trình biên dịch C, tất cả điều này được xử lý dưới vỏ bọc.

Ngoài ra, bạn phải xem độ sâu ngăn xếp của bạn. Tại bất kỳ thời điểm nào khi ngắt được kích hoạt, ISR có thể sử dụng nhiều ngăn xếp hơn là hiển nhiên bằng cách xem mã địa phương. Tất nhiên, điều này thực sự không xuất hiện nhiều trừ khi bạn đang đẩy bộ nhớ của mình đến giới hạn của nó.

Dưới đây là một liên kết mô tả quá trình này nếu bạn muốn một tài liệu tham khảo.


Mục đích của các bước 5/6 là gì? Tôi có vẻ ngớ ngẩn khi không trực tiếp sửa đổi các thanh ghi, mặc dù tôi đoán việc lộn xộn với một số thanh ghi trong khi ngắt có thể tạo ra một số kết quả khó chịu.
Chim cánh cụt vô danh

1
Bước 5 và 6 lưu trạng thái hiện tại (trước khi ngắt) của hệ thống, để có thể khôi phục (bước 8 và 9) sau khi ngắt hoàn thành, để cho phép chương trình chính tiếp tục như thể nó không bị gián đoạn.
Peter Bennett

1
Đây là một bản tóm tắt tuyệt vời.
Sói Connor

3
Điều đáng chú ý là, nếu bạn thực sự, thực sự biết bạn đang làm gì, bạn có thể vô hiệu hóa việc lưu tự động trạng thái và các thanh ghi khác, bằng cờ GCC ( ISR_NAKED). Điều này có thể cho phép bạn bỏ qua các bước 5,6,8,9, trong bối cảnh bạn thực sự cần những chu trình đó. Nhược điểm là bạn phải tuyệt đối chắc chắn rằng bạn sẽ giữ bất kỳ thanh ghi liên quan nào, hoặc có thể ghi đè lên chúng mà không gây hại.
Sói Connor

2
Thật thú vị khi biết, nhưng tôi sẽ lập trình lắp ráp trước khi sử dụng cờ đó. Thật nguy hiểm ...
thượng cổ
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.