Tôi có thể làm gì nếu hết bộ nhớ Flash hoặc SRAM?


28

Theo tài liệu của Arduino, ATmega328 có bộ nhớ Flash 32KB cho bộ tải khởi động + bản phác thảo được tải lên và chỉ có 2KB SRAM cho dữ liệu thời gian chạy. ATmega2560 có nhiều hơn một chút, tổng cộng lần lượt là 256KB và 8KB.

Trong cả hai trường hợp, những giới hạn đó có vẻ khá nhỏ, đặc biệt là khi so sánh với các thiết bị tiêu dùng có kích thước tương tự, chẳng hạn như điện thoại thông minh.

Bạn có thể làm gì nếu bạn hết tiền? Ví dụ: nếu bản phác thảo của bạn quá lớn hoặc bạn cần xử lý nhiều dữ liệu (chẳng hạn như chuỗi) khi chạy? Có cách nào để mở rộng Flash hoặc SRAM không?


Hãy thử sử dụng một số tối ưu hóa biến. Một số biến khác nhau được thảo luận ở đây
TheDoctor

1
Sử dụng phạm vi phù hợp cho các biến của bạn nếu chưa làm như vậy, trình biên dịch sẽ tối ưu hóa việc sử dụng RAM cho bạn khi các biến không được sử dụng.
jippie

1
Bạn thực sự có thể sử dụng Teensy 3.2 (với Phần mềm Teensyduino), có thể so sánh với Arduino. Cho rằng bạn sắp hết RAM / PROGMEM, điều đó có nghĩa là bạn cũng có khả năng rằng những gì bạn đang cố gắng làm là đẩy Arduino của bạn. Một chiếc Teensy 3.2 không đắt hơn nhiều. nhưng có: 32bit, 72 MHz (wtf!?) 256KB FLASH và 64KB RAM và 3x UART. Không có nhiều bộ nhớ chương trình như ATmega2560, nhưng RAM và tốc độ tăng sẽ đủ.
Paul

Câu trả lời:


30

Tối ưu hóa
Lập trình cấp thấp cho các hệ thống nhúng khá khác so với lập trình cho các thiết bị có mục đích chung, chẳng hạn như máy tính và điện thoại di động. Hiệu quả (về tốc độ và không gian) quan trọng hơn nhiều vì tài nguyên ở mức cao. Điều đó có nghĩa là điều đầu tiên cần làm nếu bạn hết dung lượng là xem xét phần nào trong mã bạn có thể tối ưu hóa.

Về việc giảm mức sử dụng không gian chương trình (Flash), kích thước mã có thể khá khó để tối ưu hóa nếu bạn chưa có kinh nghiệm hoặc nếu bạn quen sử dụng lập trình cho máy tính để bàn không có xu hướng cần kỹ năng đó. Thật không may, không có cách tiếp cận 'viên đạn ma thuật' nào sẽ hoạt động trong mọi tình huống, mặc dù nó có ích nếu bạn xem xét nghiêm túc những gì bản phác thảo của bạn thực sự cần phải có. Nếu một tính năng không cần thiết, hãy lấy nó ra.

Đôi khi nó cũng hữu ích để xác định nơi nhiều phần mã của bạn giống nhau (hoặc rất giống nhau). Bạn có thể ngưng tụ chúng thành các chức năng có thể sử dụng lại có thể được gọi từ nhiều nơi. Tuy nhiên, lưu ý rằng đôi khi cố gắng tạo mã quá tái sử dụng thực sự sẽ khiến nó dài dòng hơn. Đó là một sự cân bằng khó khăn để tấn công có xu hướng đi kèm với thực tiễn. Dành thời gian để xem các thay đổi mã ảnh hưởng đến đầu ra của trình biên dịch có thể giúp ích như thế nào.

Tối ưu hóa dữ liệu thời gian chạy (SRAM) có xu hướng dễ dàng hơn một chút khi bạn đã quen với nó. Một cạm bẫy rất phổ biến đối với các lập trình viên mới bắt đầu là sử dụng quá nhiều dữ liệu toàn cầu. Bất cứ điều gì được tuyên bố ở phạm vi toàn cầu sẽ tồn tại trong toàn bộ thời gian của bản phác thảo và điều đó không phải lúc nào cũng cần thiết. Nếu một biến chỉ được sử dụng bên trong một hàm và nó không cần phải tồn tại giữa các cuộc gọi, thì hãy biến nó thành một biến cục bộ. Nếu một giá trị cần được chia sẻ giữa các hàm, hãy xem xét liệu bạn có thể chuyển nó dưới dạng tham số thay vì làm cho nó toàn cầu hay không. Bằng cách đó, bạn sẽ chỉ sử dụng SRAM cho các biến đó khi bạn thực sự cần nó.

Một kẻ giết người khác để sử dụng SRAM là xử lý văn bản (ví dụ: sử dụng Stringlớp). Nói chung, bạn nên tránh thực hiện các thao tác Chuỗi nếu có thể. Họ là những con lợn nhớ lớn. Ví dụ: nếu bạn xuất nhiều văn bản thành nối tiếp, hãy sử dụng nhiều cuộc gọi Serial.print()thay vì sử dụng nối chuỗi. Cũng cố gắng giảm số lượng chuỗi ký tự trong mã của bạn nếu có thể.

Tránh đệ quy nếu có thể là tốt. Mỗi khi một cuộc gọi đệ quy được thực hiện, nó sẽ đưa ngăn xếp một mức độ sâu hơn. Thay vào đó hãy cấu trúc lại các hàm đệ quy của bạn để lặp lại.

Sử dụng EEPROM
EEPROM được sử dụng để lưu trữ lâu dài những thứ chỉ thỉnh thoảng thay đổi. Nếu bạn cần sử dụng danh sách lớn hoặc bảng tra cứu dữ liệu cố định, thì hãy cân nhắc lưu trữ trước trong EEPROM và chỉ rút ra những gì bạn cần khi cần thiết.

Rõ ràng EEPROM khá hạn chế về kích thước và tốc độ, và có số lượng chu kỳ ghi hạn chế. Đây không phải là một giải pháp tuyệt vời cho các giới hạn dữ liệu, nhưng nó có thể đủ để giảm bớt gánh nặng cho Flash hoặc SRAM. Cũng có thể giao tiếp với bộ nhớ ngoài tương tự, chẳng hạn như thẻ SD.

Mở rộng
Nếu bạn đã sử dụng hết tất cả các tùy chọn khác, thì việc mở rộng có thể là một khả năng. Thật không may, việc mở rộng bộ nhớ Flash để tăng không gian chương trình là không thể. Tuy nhiên, nó tốt để mở rộng SRAM. Điều này có nghĩa là bạn có thể cấu trúc lại bản phác thảo của mình để giảm kích thước mã với chi phí tăng kích thước dữ liệu.

Nhận được nhiều SRAM thực sự khá đơn giản. Một tùy chọn là sử dụng một hoặc nhiều chip 23K256 . Chúng được truy cập thông qua SPI và có thư viện SpiRAM để giúp bạn sử dụng chúng. Chỉ cần cẩn thận rằng họ hoạt động ở 3,3V chứ không phải 5V!

Nếu bạn đang sử dụng Mega, bạn có thể nhận được các lá chắn mở rộng SRAM từ Lagrangian Point hoặc Rugged Circuits .


1
Bạn cũng có thể lưu trữ dữ liệu không đổi trong bộ nhớ chương trình, thay vào đó là SRAM, nếu bạn gặp vấn đề về không gian SRAM và bộ nhớ chương trình miễn phí. Xem tại đây hoặc tại đây
Connor Wolf

1
Một lựa chọn tuyệt vời khác cho EEPROM là thẻ SD. Nó chiếm một vài cổng IO nhưng nếu bạn cần một khoảng trống lớn, giả sử dữ liệu bản đồ hoặc tương tự, có thể dễ dàng trao đổi và chỉnh sửa với chương trình tùy chỉnh trên PC.
Chim cánh cụt vô danh

1
Mọi người không nên khuyến khích sử dụng SPI SRAM hoặc mở rộng RAM, nếu chúng sắp hết bộ nhớ. Đó chỉ là một sự lãng phí tiền bạc. Chọn một MCU lớn hơn sẽ rẻ hơn. Bên cạnh, hiệu suất có thể rất kém. Trước tiên, bạn nên lập dự toán sân bóng: nếu mức sử dụng RAM ước tính quá gần với giới hạn, thì bạn đang chọn sai bảng / vi điều khiển / nền tảng phát triển. Chắc chắn, việc sử dụng tốt (lưu trữ chuỗi trong flash) và tối ưu hóa (tránh sử dụng một số thư viện) có thể là những thay đổi trò chơi thực sự. Tuy nhiên tại thời điểm này tôi thấy không có lợi ích gì khi sử dụng nền tảng Phần mềm Arduino.
hack tiếp theo

24

Khi bạn tải mã của mình lên Arduino, ví dụ như Uno, nó sẽ cho bạn biết có bao nhiêu byte sử dụng trong số 32K có sẵn. Đó là bộ nhớ flash bạn có bao nhiêu (nghĩ là đĩa cứng máy tính). Trong khi chương trình của bạn đang chạy, nó sử dụng cái gọi là SRAM và có rất ít thứ có sẵn.

Đôi khi bạn sẽ nhận thấy chương trình của bạn hoạt động kỳ quặc tại một thời điểm mà bạn thậm chí không chạm vào trong một thời gian. Có thể là những thay đổi gần đây nhất của bạn khiến nó hết bộ nhớ (SRAM). Dưới đây là một vài mẹo về cách giải phóng một số SRAM.

Lưu trữ chuỗi trong Flash thay vì SRAM.

Một trong những điều phổ biến nhất mà tôi thấy là chip hết bộ nhớ vì có quá nhiều chuỗi dài.

Sử dụng F()chức năng khi sử dụng chuỗi để chúng được lưu trữ trong Flash thay vì SRAM, vì bạn có sẵn nhiều hơn thế.

Serial.println(F("This string will be stored in flash memory"));

Sử dụng đúng kiểu dữ liệu

Bạn có thể lưu một byte bằng cách chuyển từ int(2 byte) sang byte(1 byte). Một byte không dấu sẽ cung cấp cho bạn 0-255 vì vậy nếu bạn có các số không vượt quá 255, hãy lưu một byte!

Làm sao tôi biết mình sắp hết bộ nhớ?

Thông thường, bạn sẽ quan sát chương trình của mình hoạt động kỳ lạ và tự hỏi điều gì đã xảy ra ... Bạn đã không thay đổi bất cứ điều gì trong mã gần điểm mà nó gây rối, vậy điều gì mang lại? Nó sắp hết bộ nhớ rồi.

Có một vài chức năng để cho bạn biết bạn có bao nhiêu bộ nhớ khả dụng.

Bộ nhớ khả dụng


Bạn có biết nếu F()đó là một chức năng cụ thể của Arduino hoặc nó có trong các thư viện AVR không? Bạn có thể xem xét để đề cập PROGMEM const ...quá.
jippie

Ngoài ra, bạn có thể sử dụng các cấu trúc bit để giảm thêm không gian được sử dụng bởi các biến của mình 5eg nếu bạn xử lý nhiều boolean).
jfpoilpret

17

Ngoài những gì người khác đã nói (mà tôi hoàn toàn đồng ý), tôi sẽ khuyên bạn nên đọc bài viết này về trí nhớ; nó được viết tốt, giải thích rất nhiều điều về bộ nhớ và cung cấp gợi ý về cách tối ưu hóa nó.

Vào cuối bài đọc, tôi nghĩ bạn sẽ nhận được câu trả lời khá đầy đủ cho câu hỏi của bạn.

Để tổng hợp, bạn có 2 mục tiêu tối ưu hóa có thể (tùy thuộc vào vị trí của bạn có vấn đề về bộ nhớ):

  • Flash (tức là Bộ nhớ chương trình); về điều này, bạn có thể:
    • xóa mã chết (ví dụ: bất kỳ mã nào được bao gồm nhưng không được sử dụng) và các biến không được sử dụng (mã đó cũng giúp với SRAM)
    • nhân tố ra mã trùng lặp
    • loại bỏ hoàn toàn bộ tải khởi động (bạn có thể tăng từ 0,5K cho UNO và 2 hoặc 4K cho các mẫu Arduino khác); Điều này có một số nhược điểm mặc dù
  • SRAM (tức là stack, heap và dữ liệu tĩnh); cho điều này bạn có thể:
    • loại bỏ các biến không sử dụng
    • tối ưu hóa kích thước của từng biến (ví dụ: không sử dụng dài -4 byte- nếu bạn chỉ cần int -2 byte)
    • sử dụng phạm vi phù hợp cho các biến của bạn (và thích ngăn xếp dữ liệu tĩnh khi có thể)
    • giảm kích thước bộ đệm đến mức tối thiểu
    • di chuyển dữ liệu không đổi sang PROGMEM (tức là dữ liệu tĩnh của bạn sẽ ở trong bộ nhớ Flash và sẽ không được sao chép sang SRAM khi bắt đầu chương trình); cũng áp dụng cho các chuỗi không đổi mà bạn có thể sử dụng F()macro)
    • tránh phân bổ động nếu không thực sự cần thiết; bạn sẽ tránh được một đống phân mảnh có thể không co lại ngay cả sau khi giải phóng bộ nhớ

Một cách tiếp cận bổ sung để giảm việc sử dụng SRAM cũng được mô tả (nhưng hiếm khi được sử dụng, vì nó hơi nặng khi mã hóa và không hiệu quả lắm), nó bao gồm sử dụng EEPROM để lưu trữ dữ liệu được xây dựng bởi chương trình của bạn, nhưng không được sử dụng cho đến sau này khi một số điều kiện xảy ra, khi dữ liệu có thể được tải lại từ EEPROM.


1
Xóa mã chết - trình biên dịch thực sự tốt trong việc xử lý việc này cho bạn - nó sẽ không tạo ra bất kỳ sự khác biệt nào nếu bạn có nhiều mã chưa từng được gọi. Nếu bạn vô tình gọi mã mà bạn không cần, thì dĩ nhiên là khác.
DethSwatch

9

Có hai điều cần làm nếu bạn hết dung lượng:

  • Bằng cách nào đó "tối ưu hóa" mã của bạn để nó cần ít bộ nhớ hơn; hoặc ít nhất sử dụng ít hơn loại lưu trữ cụ thể mà bạn đã hết (và sử dụng nhiều loại lưu trữ hơn mà bạn vẫn còn nhiều). Hoặc là,
  • Thêm dung lượng lưu trữ.

Có rất nhiều lời khuyên trực tuyến về cách thực hiện đầu tiên (và đối với phần lớn mọi thứ mọi người làm với Arduino, bộ lưu trữ tích hợp là quá đủ sau khi "tối ưu hóa"). Vì vậy, tôi sẽ tập trung vào thứ hai:

Có 3 thứ sử dụng hết flash hoặc SRAM; mỗi người cần một cách tiếp cận hơi khác nhau để thêm dung lượng:

  • lưu trữ biến: có thể mở rộng SRAM, vì sachleen đã chỉ ra. SRAM, FRAM và NVSRAM đều thích hợp cho các biến thay đổi nhanh chóng. (Mặc dù về nguyên tắc bạn có thể sử dụng đèn flash để lưu trữ các biến, sau đó bạn phải lo lắng về sự hao mòn của đèn flash). SPI (một giao thức nối tiếp) là cách dễ nhất để kết nối với Arduino. Các thư viện SpiRAM làm việc với các Microchip 23K256 con chip SRAM nối tiếp. Chip FRAM nối tiếp Ramtron FM25W256 (hiện thuộc sở hữu của Cypress) cũng sử dụng SPI. Cypress CY14B101 NVSRAM cũng sử dụng SPI. V.v.

  • dữ liệu không đổi cần phải có ở lần tiếp theo khi bật nguồn: điều này gần như đơn giản như mở rộng SRAM. Có nhiều thiết bị lưu trữ EEPROM, FRAM, NVSRAM và FLASH bên ngoài . Hiện tại chi phí thấp nhất cho mỗi MB là thẻ flash SD (có thể truy cập qua SPI). Ramtron FM25W256 (xem ở trên), Cypress CY14B101 (xem ở trên), vv cũng có thể lưu trữ dữ liệu không đổi. Nhiều lá chắn mở rộng bao gồm khe cắm thẻ SD, và một số thư việnhướng dẫn hỗ trợ đọc và ghi vào (flash) thẻ SD. (Chúng tôi không thể sử dụng SRAM cho việc này, vì SRAM quên mọi thứ khi mất điện).

  • mã thực thi: Thật không may, việc mở rộng bộ nhớ Flash của Arduino để tăng không gian chương trình là không thể. Tuy nhiên, một lập trình viên luôn có thể cấu trúc lại một bản phác thảo để giảm kích thước mã với chi phí tăng kích thước dữ liệu và làm cho nó chạy chậm hơn một chút. (Về lý thuyết, bạn có thể dịch toàn bộ bản phác thảo của mình sang một số ngôn ngữ được dịch, lưu trữ phiên bản phác thảo đó trên thẻ SD, sau đó viết một trình thông dịch cho ngôn ngữ đó chạy trên Arduino để tìm nạp và thực hiện các hướng dẫn từ Thẻ SD - Forth trên Arduino , trình thông dịch BASIC, trình thông dịch Tom Napier Picaro, một số ngôn ngữ dành riêng cho ứng dụng, v.v.).

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.