Sử dụng ngăn xếp ATTiny2313 ISR


7

Tôi đang sử dụng ATTiny2313 để hoạt động như một bộ tập trung nối tiếp. Nó chỉ có 128byte RAM. Tôi nghĩ rằng tôi sắp hết RAM trong ISR. Câu hỏi của tôi là ISR sử dụng bao nhiêu RAM (stack) để lưu bối cảnh (các thanh ghi). Tức là nếu tôi sử dụng ISR, tôi sẽ còn lại bao nhiêu trong số 128 byte. Có cách nào để phát hiện tràn ngăn xếp?

Câu trả lời:


9

Chà, kiểm tra tài liệu ATTiny2313 , ở trang 15, nó ghi:

Đáp ứng thực thi ngắt cho tất cả các ngắt AVR được kích hoạt là tối thiểu bốn chu kỳ xung nhịp. Sau bốn chu kỳ, địa chỉ vectơ chương trình cho thói quen xử lý ngắt thực tế được thực thi. Trong khoảng thời gian bốn chu kỳ đồng hồ này, Bộ đếm chương trình được đẩy lên Stack. Vectơ thường là một bước nhảy đến thói quen ngắt và bước nhảy này mất ba chu kỳ đồng hồ. Nếu một ngắt xảy ra trong khi thực hiện lệnh đa chu kỳ, lệnh này được hoàn thành trước khi ngắt được phục vụ. Nếu ngắt xảy ra khi MCU ở chế độ ngủ, thời gian đáp ứng thực hiện ngắt được tăng thêm bốn chu kỳ xung nhịp. Sự gia tăng này đi kèm với thời gian khởi động từ chế độ ngủ được chọn.

Một sự trở lại từ một thói quen xử lý ngắt mất bốn chu kỳ đồng hồ. Trong bốn chu kỳ xung nhịp này, Bộ đếm chương trình (hai byte) được bật trở lại từ Stack, Con trỏ ngăn xếp được tăng lên hai và I-bit trong SREG được đặt.

Do đó, bạn thực sự chỉ nhìn vào 2 byte trên ngăn xếp trong khi ngắt (PC); bất cứ điều gì khác mà ISR đặt lên ngăn xếp đều tùy thuộc vào chính ISR. Tôi sẽ không mong đợi một trình xử lý ngắt được viết tốt sẽ cần rất nhiều không gian ngăn xếp.

Đối với chính Con trỏ ngăn xếp, trên trang 13, nó ghi:

Stack chủ yếu được sử dụng để lưu trữ dữ liệu tạm thời, để lưu trữ các biến cục bộ và lưu trữ địa chỉ trả về sau khi bị gián đoạn và các cuộc gọi chương trình con. Thanh ghi con trỏ ngăn xếp luôn luôn chỉ đến đỉnh của ngăn xếp. Lưu ý rằng Stack được triển khai khi phát triển từ các vị trí bộ nhớ cao hơn đến các vị trí bộ nhớ thấp hơn. Điều này ngụ ý rằng lệnh Stack PUSH làm giảm con trỏ Stack.

Con trỏ ngăn xếp trỏ đến khu vực ngăn xếp SRAM dữ liệu nơi đặt các ngăn con và ngăn gián đoạn. Không gian ngăn xếp này trong SRAM dữ liệu phải được chương trình xác định trước khi thực hiện bất kỳ lệnh gọi chương trình con nào hoặc ngắt được kích hoạt. Con trỏ ngăn xếp phải được đặt thành điểm trên 0x60. Con trỏ ngăn xếp bị giảm bởi một khi dữ liệu được đẩy lên Stack bằng lệnh PUSH và nó bị giảm xuống hai khi địa chỉ trả về được đẩy lên Stack với lệnh gọi hoặc ngắt chương trình con. Con trỏ ngăn xếp được tăng thêm một khi dữ liệu được bật từ Stack với lệnh POP và nó được tăng lên hai khi dữ liệu được bật từ Stack với sự trở lại từ RETI của chương trình con hoặc trở về từ RETI ngắt.

Con trỏ ngăn xếp AVR được triển khai như hai thanh ghi 8 bit trong không gian I / O. Số lượng bit thực sự được sử dụng là phụ thuộc thực hiện. Lưu ý rằng không gian dữ liệu trong một số triển khai của kiến ​​trúc AVR nhỏ đến mức chỉ cần SPL. Trong trường hợp này, Đăng ký SPH sẽ không có mặt.

Trong trường hợp của bạn, tôi nghĩ chỉ có SPL hiện tại (128 byte RAM = 7 bit).

Ngoài phần cứng, nó phụ thuộc vào khung của bạn, mà đối với hầu hết các bộ phận AVR sẽ liên quan đến GCC, GNU Binutilsavr-libc . Một cái nhìn nhanh về Câu hỏi thường gặp avr-libc đã đưa ra hai câu hỏi hay:

http://www.nongnu.org/avr-libc/user-manual/FAQ.html#faq_reg_usage

Những thanh ghi nào được sử dụng bởi trình biên dịch C?

  • Kiểu dữ liệu: char là 8 bit, int là 16 bit, dài là 32 bit, dài là 64 bit, float và double là 32 bit (đây là định dạng dấu phẩy động được hỗ trợ duy nhất), con trỏ là 16 bit (con trỏ hàm là từ địa chỉ, để cho phép giải quyết không gian bộ nhớ chương trình lên tới 128K). Có một tùy chọn -mint8 (xem Tùy chọn cho trình biên dịch C avr-gcc) để tạo int 8 bit, nhưng điều đó không được avr-libc hỗ trợ và vi phạm tiêu chuẩn C (int phải có ít nhất 16 bit). Nó có thể được gỡ bỏ trong một bản phát hành trong tương lai.

  • Các thanh ghi sử dụng cuộc gọi (r18-r27, r30-r31): Có thể được phân bổ bởi gcc cho dữ liệu cục bộ. Bạn có thể sử dụng chúng một cách tự do trong chương trình con chương trình biên dịch chương trình. Gọi chương trình con C có thể ghi đè bất kỳ trong số chúng - người gọi có trách nhiệm lưu và khôi phục.

  • Các thanh ghi lưu cuộc gọi (r2-r17, r28-r29): Có thể được phân bổ bởi gcc cho dữ liệu cục bộ. Gọi chương trình con C không thay đổi. Chương trình con chương trình biên dịch có trách nhiệm lưu và khôi phục các thanh ghi này, nếu thay đổi. r29: r28 (con trỏ Y) được sử dụng làm con trỏ khung (trỏ đến dữ liệu cục bộ trên ngăn xếp) nếu cần. Yêu cầu cho callee để lưu / lưu giữ nội dung của các thanh ghi này thậm chí áp dụng trong các tình huống trong đó trình biên dịch gán chúng cho việc truyền đối số.

  • Các thanh ghi cố định (r0, r1): Không bao giờ được phân bổ bởi gcc cho dữ liệu cục bộ, nhưng thường được sử dụng cho các mục đích cố định:

    r0 - thanh ghi tạm thời, có thể bị ghi đè bởi bất kỳ mã C nào (ngoại trừ các trình xử lý ngắt lưu nó), có thể được sử dụng để ghi nhớ một cái gì đó trong một đoạn mã trình biên dịch mã

    r1 - được coi là luôn luôn bằng 0 trong bất kỳ mã C nào, có thể được sử dụng để ghi nhớ một cái gì đó trong một đoạn mã trình biên dịch mã, nhưng sau đó phải được xóa sau khi sử dụng (clr r1). Điều này bao gồm bất kỳ việc sử dụng các hướng dẫn [f] mul [s [u]], trả về kết quả của chúng trong r1: r0. Trình xử lý ngắt lưu và xóa r1 khi nhập và khôi phục r1 khi thoát (trong trường hợp nó khác không).

  • Các quy ước gọi hàm: Đối số - được phân bổ từ trái sang phải, r25 đến r8. Tất cả các đối số được căn chỉnh để bắt đầu trong các thanh ghi có số chẵn (các đối số có kích thước lẻ, bao gồm char, có một thanh ghi miễn phí ở trên chúng). Điều này cho phép sử dụng tốt hơn các lệnh Movw trên lõi nâng cao.

Nếu quá nhiều, những thứ không phù hợp sẽ được chuyển vào ngăn xếp.

Giá trị trả về: 8 bit trong r24 (không phải r25!), 16 bit trong r25: r24, tối đa 32 bit trong r22-r25, tối đa 64 bit trong r18-r25. Các giá trị trả về 8 bit là 0 / ký hiệu được mở rộng đến 16 bit bởi hàm được gọi (char không dấu là hiệu quả hơn char đã ký - chỉ clr r25). Các đối số cho các hàm với danh sách đối số biến (printf, v.v.) đều được truyền vào stack và char được mở rộng thành int.

http://www.nongnu.org/avr-libc/user-manual/FAQ.html#faq_ramoverlap

Làm thế nào để phát hiện bộ nhớ RAM và các vấn đề chồng chéo biến đổi? Bạn chỉ có thể chạy avr-nm trên tệp đầu ra (ELF). Chạy nó với tùy chọn -n và nó sẽ sắp xếp các ký hiệu bằng số (theo mặc định, chúng được sắp xếp theo thứ tự abc).

Tìm ký hiệu _end, đó là địa chỉ đầu tiên trong RAM không được cấp phát bởi một biến. (avr-gcc bên trong thêm 0x800000 vào tất cả các địa chỉ biến dữ liệu / bss, vì vậy vui lòng bỏ qua phần bù này.) Sau đó, mã khởi tạo thời gian chạy khởi tạo con trỏ ngăn xếp (theo mặc định) để trỏ đến địa chỉ khả dụng cuối cùng trong SRAM (bên trong) . Do đó, khu vực giữa _end và kết thúc SRAM là những gì có sẵn cho stack. (Nếu ứng dụng của bạn sử dụng malloc (), ví dụ như cũng có thể xảy ra bên trong printf (), heap cho bộ nhớ động cũng nằm ở đó. Xem Vùng nhớ và Sử dụng malloc ().)

Số lượng ngăn xếp cần thiết cho ứng dụng của bạn không thể được xác định dễ dàng. Ví dụ, nếu bạn gọi đệ quy một hàm và quên ngắt đệ quy đó, số lượng ngăn xếp cần thiết là vô hạn. :-) Bạn có thể xem mã trình biên dịch được tạo (avr-gcc ... -S), có một nhận xét trong mỗi tệp trình biên dịch được tạo cho bạn biết kích thước khung cho mỗi hàm được tạo. Đó là số lượng ngăn xếp cần thiết cho chức năng này, bạn phải thêm vào đó cho tất cả các chức năng mà bạn biết rằng các cuộc gọi có thể được lồng vào nhau.


Có - nhưng trình biên dịch avr gcc sẽ lập trình đăng ký lưu / khôi phục vào ISR phải không?
JohnC

Có lẽ - hãy xem những gì tôi đã thêm về đăng ký, ngăn xếp và sử dụng RAM. Nếu bạn thực sự lo lắng, tôi khuyên bạn nên tạo nguồn lắp ráp (gcc -S foo.c) và kiểm tra chi tiết.
Craig Trader
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.