Apa yang bisa saya lakukan jika kehabisan memori Flash atau SRAM?

28

Menurut dokumentasi Arduino, ATmega328 memiliki 32KB memori Flash untuk bootloader + sketsa yang diunggah, dan hanya 2KB SRAM untuk data runtime. ATmega2560 memiliki sedikit lebih banyak, dengan total 256KB dan 8KB.

Dalam kedua kasus tersebut, batasan tersebut tampak agak kecil, terutama jika dibandingkan dengan perangkat konsumen berukuran sama, seperti smartphone.

Apa yang dapat Anda lakukan jika Anda kehabisan? Misalnya jika sketsa Anda terlalu besar, atau Anda perlu memproses banyak data (seperti string) saat runtime? Apakah ada cara untuk memperluas Flash atau SRAM?

Peter Bloomfield
sumber
Coba gunakan beberapa optimasi variabel. Beberapa variabel berbeda dibahas di sini
TheDoctor
1
Gunakan cakupan yang tepat untuk variabel Anda jika belum melakukannya, kompiler akan mengoptimalkan penggunaan RAM untuk Anda ketika variabel tidak digunakan.
jippie
1
Anda mungkin benar-benar menggunakan Teensy 3.2 (dengan Perangkat Lunak Teensyduino), yang akan sebanding dengan Arduino. Mengingat Anda kehabisan RAM / PROGMEM, itu berarti bahwa Anda juga cenderung melakukan apa yang sedang Anda lakukan adalah mendorong Arduino Anda. A Teensy 3.2 tidak jauh lebih mahal. tetapi memiliki: 32bit, 72MHz (wtf !?) 256KB FLASH dan 64KB RAM dan 3x UART. Tidak lebih banyak memori program seperti ATmega2560, tetapi peningkatan RAM dan kecepatan sudah cukup.
Paul

Jawaban:

30

Optimasi
Pemrograman tingkat rendah untuk sistem tertanam sangat berbeda dari pemrograman untuk perangkat tujuan umum, seperti komputer dan ponsel. Efisiensi (dalam hal kecepatan dan ruang) jauh lebih penting karena sumber daya berada pada premium. Itu berarti hal pertama yang harus dilakukan jika Anda kehabisan ruang adalah untuk melihat bagian mana dari kode Anda yang dapat Anda optimalkan.

Dalam hal mengurangi penggunaan ruang program (Flash), ukuran kode bisa sangat sulit untuk dioptimalkan jika Anda tidak berpengalaman, atau jika Anda lebih terbiasa pemrograman untuk komputer desktop yang tidak cenderung membutuhkan keterampilan itu. Sayangnya, tidak ada pendekatan 'peluru ajaib' yang akan bekerja untuk semua situasi, meskipun akan membantu jika Anda mempertimbangkan dengan serius apa yang sebenarnya perlu dimiliki sketsa Anda . Jika fitur tidak diperlukan, keluarkan.

Terkadang juga membantu untuk mengidentifikasi di mana beberapa bagian kode Anda sama (atau sangat mirip). Anda mungkin dapat menyingkatnya menjadi fungsi yang dapat digunakan kembali yang dapat dipanggil dari berbagai tempat. Namun, perlu diketahui bahwa kadang-kadang mencoba membuat kode terlalu dapat digunakan kembali akhirnya membuatnya menjadi lebih bertele-tele. Ini keseimbangan yang sulit untuk dipukul yang cenderung disertai dengan latihan. Menghabiskan waktu untuk melihat bagaimana perubahan kode mempengaruhi output kompiler dapat membantu.

Optimalisasi data Runtime (SRAM) cenderung sedikit lebih mudah ketika Anda terbiasa. Jebakan yang sangat umum untuk programmer pemula menggunakan terlalu banyak data global. Apa pun yang dinyatakan pada lingkup global akan ada selama sketsa seumur hidup, dan itu tidak selalu diperlukan. Jika variabel hanya digunakan di dalam satu fungsi, dan itu tidak perlu bertahan di antara panggilan, maka jadikan itu variabel lokal. Jika suatu nilai perlu dibagi di antara berbagai fungsi, pertimbangkan apakah Anda dapat meneruskannya sebagai parameter alih-alih menjadikannya global. Dengan begitu Anda hanya akan menggunakan SRAM untuk variabel-variabel tersebut saat Anda benar-benar membutuhkannya.

Pembunuh lain untuk penggunaan SRAM adalah pemrosesan teks (misalnya menggunakan Stringkelas). Secara umum, Anda harus menghindari melakukan operasi String jika memungkinkan. Mereka adalah babi memori besar. Misalnya, jika Anda mengeluarkan banyak teks ke serial, gunakan beberapa panggilan untuk Serial.print()bukannya menggunakan penggabungan string. Coba juga untuk mengurangi jumlah string literal dalam kode Anda jika memungkinkan.

Hindari rekursi jika memungkinkan juga. Setiap kali panggilan rekursif dilakukan, dibutuhkan tingkat stack yang lebih dalam. Refactor fungsi rekursif Anda untuk menjadi iteratif sebagai gantinya.

Gunakan EEPROM
EEPROM digunakan untuk penyimpanan jangka panjang hal-hal yang hanya berubah sesekali. Jika Anda perlu menggunakan daftar besar atau mencari tabel data tetap, maka pertimbangkan untuk menyimpannya di EEPROM terlebih dahulu, dan hanya menarik apa yang Anda butuhkan saat diperlukan.

Jelas EEPROM cukup terbatas dalam ukuran dan kecepatan, dan memiliki jumlah siklus tulis yang terbatas. Ini bukan solusi yang bagus untuk keterbatasan data, tetapi mungkin cukup untuk meringankan beban pada Flash atau SRAM. Sangat mungkin juga untuk berinteraksi dengan penyimpanan eksternal yang serupa, seperti kartu SD.

Ekspansi
Jika Anda telah kehabisan semua opsi lain, ekspansi mungkin menjadi suatu kemungkinan. Sayangnya, memperluas memori Flash untuk menambah ruang program tidak dimungkinkan. Namun, adalah mungkin untuk memperluas SRAM. Ini berarti Anda mungkin dapat memperbaiki sketsa Anda untuk mengurangi ukuran kode dengan mengorbankan peningkatan ukuran data.

Mendapatkan lebih banyak SRAM sebenarnya cukup mudah. Salah satu opsi adalah menggunakan satu atau lebih chip 23K256 . Mereka diakses melalui SPI, dan ada perpustakaan SpiRAM untuk membantu Anda menggunakannya. Berhati-hatilah karena mereka beroperasi pada 3.3V, bukan 5V!

Jika Anda menggunakan Mega, Anda bisa mendapatkan pelindung ekspansi SRAM dari Lagrangian Point atau Rugged Circuits .

Peter Bloomfield
sumber
1
Anda juga dapat menyimpan data konstan dalam memori program, daripada SRAM, jika Anda memiliki masalah ruang SRAM dan mengosongkan memori program. Lihat di sini atau di sini
Connor Wolf
1
Alternatif hebat lain untuk EEPROM adalah kartu SD. Memang membutuhkan beberapa port IO tetapi jika Anda memang membutuhkan ruang yang besar untuk, katakanlah data peta atau sejenisnya, dapat dengan mudah bertukar dan mengedit dengan program khusus pada PC.
Penguin Anonim
1
Orang seharusnya tidak didorong untuk menggunakan SPI SRAM atau ekspansi RAM, jika kehabisan memori. Itu hanya buang-buang uang. Memilih MCU yang lebih besar akan lebih murah. Selain itu, kinerjanya bisa sangat buruk. Pertama-tama seseorang harus membuat perkiraan rata-rata: jika perkiraan penggunaan RAM terlalu dekat dengan batas, maka Anda memilih platform board / mikrokontroler / pengembangan yang salah. Tentu, penggunaan yang baik (menyimpan string dalam flash) dan optimisasi (menghindari penggunaan beberapa pustaka) dapat menjadi pengubah game yang sebenarnya. Namun pada titik ini saya tidak melihat manfaat menggunakan platform Perangkat Lunak Arduino.
next-hack
24

Ketika Anda mengunggah kode Anda ke Arduino Anda, ucapkan Uno misalnya, itu akan memberi tahu Anda berapa banyak byte yang digunakan dari 32K yang tersedia. Itu adalah berapa banyak memori flash yang Anda miliki (pikirkan hard disk komputer). Saat program Anda berjalan, ia menggunakan apa yang disebut SRAM, dan ada jauh lebih sedikit dari yang tersedia.

Terkadang Anda akan melihat program Anda bertingkah aneh pada titik yang bahkan belum pernah Anda sentuh. Bisa jadi perubahan terbaru Anda menyebabkannya kehabisan memori (SRAM). Berikut adalah beberapa tips tentang cara membebaskan SRAM.

Menyimpan string dalam Flash bukan SRAM.

Salah satu hal paling umum yang saya lihat adalah chip kehabisan memori karena ada terlalu banyak string panjang.

Gunakan F()fungsi ketika menggunakan string sehingga mereka disimpan dalam Flash bukan SRAM, karena Anda memiliki lebih banyak dari yang tersedia.

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

Gunakan tipe data yang tepat

Anda dapat menyimpan byte dengan beralih dari int(2 byte) ke byte(1 byte). Byte yang tidak ditandatangani akan memberi Anda 0-255 jadi jika Anda memiliki angka yang tidak lebih tinggi dari 255, simpan byte!

Bagaimana saya tahu saya kehabisan memori?

Biasanya Anda akan mengamati program Anda bertingkah aneh dan bertanya-tanya apa yang salah ... Anda tidak mengubah apa pun dalam kode di dekat titik di mana itu kacau, jadi apa yang menyebabkannya? Kehabisan memori.

Ada beberapa fungsi untuk memberi tahu Anda berapa banyak memori yang tersedia yang Anda miliki.

Memori yang tersedia

sachleen
sumber
Apakah Anda tahu jika F()masalahnya adalah fungsi spesifik Arduino atau ada di perpustakaan AVR? Anda dapat mempertimbangkan untuk menyebutkan PROGMEM const ...juga.
jippie
Anda juga dapat menggunakan struktur bit untuk lebih mengurangi ruang yang digunakan oleh variabel Anda 5eg jika Anda berurusan dengan banyak boolean).
jfpoilpret
17

Selain apa yang dikatakan orang lain (yang saya setujui sepenuhnya), saya akan menyarankan untuk membaca artikel AdWords tentang memori ini; itu ditulis dengan baik, menjelaskan banyak hal tentang memori dan memberikan petunjuk tentang cara mengoptimalkannya.

Di akhir bacaan, saya pikir Anda akan mendapatkan jawaban yang cukup lengkap untuk pertanyaan Anda.

Singkatnya, Anda memiliki 2 target optimasi yang mungkin (tergantung di mana masalah memori Anda berada):

  • Flash (yaitu Memori Program); untuk ini, Anda dapat:
    • menghapus kode mati (mis. kode apa pun yang disertakan tetapi tidak digunakan) dan variabel yang tidak digunakan (yang juga membantu dengan SRAM)
    • faktor keluar kode digandakan
    • hapus bootloader sama sekali (Anda dapat memperoleh antara 0,5K untuk UNO dan 2 atau 4K untuk model Arduino lainnya); ini memiliki beberapa kelemahan
  • SRAM (yaitu tumpukan, tumpukan dan data statis); untuk ini Anda dapat:
    • hapus variabel yang tidak digunakan
    • optimalkan ukuran setiap variabel (mis. jangan gunakan panjang -4 byte - jika Anda hanya perlu int -2 byte)
    • gunakan cakupan yang tepat untuk variabel Anda (dan lebih suka susun ke data statis bila memungkinkan)
    • kurangi ukuran buffer hingga batas minimum yang ketat
    • pindahkan data konstan ke PROGMEM (yaitu data statis Anda akan tetap dalam memori Flash dan tidak akan disalin ke SRAM saat program dimulai); itu juga berlaku untuk string konstan yang bisa Anda gunakan F()makro)
    • hindari alokasi dinamis jika tidak mutlak diperlukan; Anda akan menghindari tumpukan yang terfragmentasi yang mungkin tidak menyusut bahkan setelah membebaskan memori

Pendekatan tambahan untuk mengurangi penggunaan SRAM juga dijelaskan (tetapi jarang digunakan, karena agak berat ketika pengkodean dan tidak sangat efisien), itu termasuk menggunakan EEPROM untuk menyimpan data yang dibangun oleh program Anda, tetapi tidak digunakan sampai nanti ketika beberapa kondisi terjadi, ketika data dapat dimuat kembali dari EEPROM.

jfpoilpret
sumber
1
Menghapus kode mati - kompiler benar - benar bagus dalam menangani ini untuk Anda - tidak akan ada bedanya jika Anda memiliki banyak kode yang tidak pernah dipanggil. Jika Anda secara tidak sengaja memanggil kode yang tidak Anda butuhkan, maka itu berbeda, tentu saja.
dethSwatch
9

Ada dua hal yang harus dilakukan jika Anda kehabisan penyimpanan:

  • Entah bagaimana "mengoptimalkan" kode Anda sehingga membutuhkan lebih sedikit penyimpanan; atau setidaknya menggunakan kurang dari jenis penyimpanan tertentu yang Anda kehabisan (dan menggunakan lebih banyak jenis penyimpanan yang masih Anda miliki). Atau,
  • Tambahkan lebih banyak penyimpanan.

Ada banyak kiat daring tentang cara melakukan yang pertama (dan untuk sebagian besar hal yang dilakukan orang dengan Arduino, penyimpanan bawaan lebih dari cukup setelah "mengoptimalkan"). Jadi saya akan fokus pada yang kedua:

Ada 3 hal yang menggunakan flash atau SRAM; masing-masing memerlukan pendekatan yang sedikit berbeda untuk menambahkan penyimpanan:

  • penyimpanan variabel: dimungkinkan untuk memperluas SRAM, seperti yang telah ditunjukkan oleh sachleen. SRAM, FRAM, dan NVSRAM semuanya sesuai untuk variabel yang berubah dengan cepat. (Meskipun pada prinsipnya Anda bisa menggunakan flash untuk menyimpan variabel, maka Anda harus khawatir tentang flash yang aus). SPI (protokol serial) adalah yang termudah untuk terhubung ke Arduino. The perpustakaan SpiRAM bekerja dengan Microchip 23K256 Chip SRAM serial. Chip FRAM serial Ramtron FM25W256 (sekarang dimiliki oleh Cypress) juga menggunakan SPI. The Cypress CY14B101 NVSRAM juga menggunakan SPI. Dll

  • data konstan yang perlu tetap ada di sana saat daya dinyalakan: ini hampir sesederhana memperluas SRAM. Ada banyak perangkat penyimpanan EEPROM eksternal , FRAM, NVSRAM, dan FLASH . Saat ini biaya terendah per MB adalah kartu flash SD (yang dapat diakses melalui SPI). Ramtron FM25W256 (lihat di atas), Cypress CY14B101 (lihat di atas), dll. Juga dapat menyimpan data konstan. Banyak perisai ekspansi termasuk slot kartu SD, dan beberapa perpustakaan dan tutorial mendukung membaca dan menulis ke (flash) kartu SD. (Kami tidak dapat menggunakan SRAM untuk ini, karena SRAM melupakan segalanya ketika listrik padam).

  • kode yang dapat dieksekusi: Sayangnya, memperluas memori Flash Arduino untuk menambah ruang program tidak dimungkinkan. Namun, seorang programmer selalu dapat membuat ulang sketsa untuk mengurangi ukuran kode dengan mengorbankan peningkatan ukuran data dan membuatnya berjalan sedikit lebih lambat. (Secara teori, Anda bisa menerjemahkan seluruh sketsa Anda ke dalam bahasa yang ditafsirkan, menyimpan versi sketsa Anda pada kartu SD, dan kemudian menulis penerjemah untuk bahasa yang berjalan di Arduino untuk mengambil dan menjalankan instruksi dari Kartu SD - Untuk Arduino , juru bahasa BASIC, juru bahasa Tom Napier Picaro, beberapa bahasa khusus aplikasi, dll.).

David Cary
sumber