ฉันจะทำอย่างไรถ้าฉันไม่มีหน่วยความจำแฟลชหรือ SRAM


28

ตามเอกสารของ Arduino ATmega328 มีหน่วยความจำแฟลช 32KB สำหรับ bootloader + อัพโหลดร่างและเพียง 2KB SRAM สำหรับข้อมูลรันไทม์ ATmega2560 มีจำนวนมากกว่า 256KB และ 8KB ตามลำดับ

ไม่ว่าในกรณีใดข้อ จำกัด เหล่านั้นดูเหมือนจะค่อนข้างเล็กโดยเฉพาะเมื่อเปรียบเทียบกับอุปกรณ์ผู้บริโภคที่มีขนาดใกล้เคียงกันเช่นสมาร์ทโฟน

คุณจะทำอย่างไรถ้าหมด? เช่นถ้าร่างของคุณใหญ่เกินไปหรือคุณต้องการประมวลผลข้อมูลจำนวนมาก (เช่นสตริง) ตอนรันไทม์? มีวิธีใดที่จะขยาย Flash หรือ SRAM หรือไม่


ลองใช้การเพิ่มประสิทธิภาพตัวแปรบางอย่าง มีการกล่าวถึงตัวแปรที่แตกต่างกันที่นี่
TheDoctor

1
ใช้ขอบเขตที่เหมาะสมสำหรับตัวแปรของคุณหากไม่ได้ทำเช่นนั้นคอมไพเลอร์จะปรับการใช้ RAM ให้เหมาะสมเมื่อคุณไม่ได้ใช้ตัวแปร
jippie

1
คุณอาจใช้ Teensy 3.2 (พร้อมกับ Teensyduino Software) ซึ่งจะเปรียบได้กับ Arduino เมื่อคุณหมด RAM / PROGMEM มันก็หมายความว่าคุณมีแนวโน้มว่าสิ่งที่คุณพยายามทำคือการผลัก Arduino ของคุณ A Teensy 3.2 นั้นไม่แพงมากนัก แต่มี: 32 บิต, 72MHz (wtf !?) 256KB FLASH และ 64KB RAM และ 3x UART หน่วยความจำของโปรแกรมไม่มากเท่ากับ ATmega2560 แต่การเพิ่ม RAM และความเร็วควรเพียงพอ
พอล

คำตอบ:


30

การเพิ่มประสิทธิภาพ
การเขียนโปรแกรมระดับต่ำสำหรับระบบฝังตัวค่อนข้างแตกต่างจากการเขียนโปรแกรมสำหรับอุปกรณ์ที่ใช้งานทั่วไปเช่นคอมพิวเตอร์และโทรศัพท์มือถือ ประสิทธิภาพ (ในแง่ของความเร็วและพื้นที่) มีความสำคัญมากกว่าเพราะทรัพยากรอยู่ในระดับพรีเมี่ยม นั่นหมายความว่าสิ่งแรกที่ต้องทำหากคุณไม่มีที่ว่างในการดูว่าส่วนใดของรหัสที่คุณสามารถเพิ่มประสิทธิภาพ

ในแง่ของการลดการใช้พื้นที่โปรแกรม (Flash) ขนาดของรหัสอาจทำได้ยากหากคุณไม่มีประสบการณ์หรือหากคุณคุ้นเคยกับการเขียนโปรแกรมสำหรับคอมพิวเตอร์เดสก์ท็อปมากขึ้นซึ่งไม่ต้องการทักษะนั้น โชคไม่ดีที่ไม่มี 'bullet เวทมนตร์' ซึ่งจะทำงานได้ในทุกสถานการณ์แม้ว่ามันจะช่วยให้คุณพิจารณาอย่างจริงจังว่าร่างของคุณต้องการอะไร หากไม่จำเป็นต้องใช้คุณสมบัติให้นำออกมา

บางครั้งการระบุว่าส่วนต่าง ๆ ของรหัสของคุณเหมือนกัน (หรือคล้ายกันมาก) เป็นประโยชน์หรือไม่ คุณอาจรวมเข้ากับฟังก์ชั่นที่ใช้ซ้ำได้ซึ่งสามารถเรียกได้จากหลาย ๆ ที่ อย่างไรก็ตามทราบว่าบางครั้งพยายามที่จะทำให้รหัสเกินไปนำมาใช้ใหม่จริงจบลงด้วยการทำให้มันมากขึ้นอย่างละเอียด มันเป็นเรื่องยากที่จะจัดการให้สมดุลซึ่งมีแนวโน้มว่าจะมาพร้อมกับการฝึกฝน ใช้เวลาดูว่าการเปลี่ยนรหัสมีผลต่อคอมไพเลอร์เอาต์พุตอย่างไรบ้าง

การเพิ่มประสิทธิภาพรันไทม์ data (SRAM) มีแนวโน้มที่จะง่ายขึ้นเล็กน้อยเมื่อคุณคุ้นเคย ข้อผิดพลาดทั่วไปสำหรับโปรแกรมเมอร์มือใหม่กำลังใช้ข้อมูลทั่วโลกมากเกินไป สิ่งใดก็ตามที่ประกาศในขอบเขตทั่วโลกจะมีอยู่ตลอดทั้งร่างและไม่จำเป็นเสมอไป หากมีการใช้ตัวแปรภายในฟังก์ชั่นเดียวเท่านั้นและไม่จำเป็นต้องคงอยู่ระหว่างการเรียกดังนั้นให้เป็นตัวแปรโลคอล หากค่าจำเป็นต้องถูกแชร์ระหว่างฟังก์ชั่นให้พิจารณาว่าคุณสามารถส่งเป็นพารามิเตอร์แทนที่จะทำให้เป็นค่าส่วนกลางหรือไม่ ด้วยวิธีนี้คุณจะใช้ SRAM สำหรับตัวแปรเหล่านั้นเมื่อคุณต้องการเท่านั้น

นักฆ่าคนอื่นสำหรับการใช้งาน SRAM คือการประมวลผลข้อความ (เช่นใช้Stringคลาส) โดยทั่วไปคุณควรหลีกเลี่ยงการใช้งาน String หากเป็นไปได้ พวกเขาเป็นหมูหน่วยความจำขนาดใหญ่ ตัวอย่างเช่นหากคุณกำลังส่งข้อความจำนวนมากไปยังซีเรียลให้ใช้การโทรหลายสายSerial.print()แทนการใช้การต่อข้อความแบบสตริง และพยายามลดจำนวนตัวอักษรสตริงในรหัสของคุณถ้าเป็นไปได้

หลีกเลี่ยงการเรียกซ้ำหากเป็นไปได้เช่นกัน ทุกครั้งที่มีการโทรซ้ำจะทำให้ระดับสแต็กลึกยิ่งขึ้น refactor ฟังก์ชั่นวนซ้ำของคุณเพื่อทำซ้ำแทน

ใช้ EEPROM
EEPROM ใช้สำหรับการจัดเก็บข้อมูลระยะยาวที่เปลี่ยนแปลงในบางครั้งเท่านั้น หากคุณต้องการใช้รายการขนาดใหญ่หรือตารางค้นหาข้อมูลคงที่ให้พิจารณาจัดเก็บไว้ใน EEPROM ล่วงหน้าและดึงสิ่งที่คุณต้องการเมื่อจำเป็นเท่านั้น

เห็นได้ชัดว่า EEPROM มีขนาดและความเร็วค่อนข้าง จำกัด และมีจำนวนรอบการเขียน จำกัด ไม่ใช่วิธีแก้ปัญหาข้อ จำกัด ด้านข้อมูลที่ยอดเยี่ยม แต่อาจเพียงพอที่จะแบ่งเบาภาระใน Flash หรือ SRAM อาจเป็นไปได้ที่จะเชื่อมต่อกับที่จัดเก็บข้อมูลภายนอกที่คล้ายกันเช่นการ์ด SD

การขยายตัว
หากคุณได้ใช้ตัวเลือกอื่นหมดแล้วการขยายตัวอาจเป็นไปได้ น่าเสียดายที่การขยายหน่วยความจำแฟลชเพื่อเพิ่มพื้นที่โปรแกรมไม่สามารถทำได้ อย่างไรก็ตามมันเป็นไปได้ที่จะขยาย SRAM ซึ่งหมายความว่าคุณสามารถ refactor ร่างของคุณเพื่อลดขนาดรหัสด้วยค่าใช้จ่ายในการเพิ่มขนาดข้อมูล

การได้รับ SRAM ที่มากขึ้นนั้นค่อนข้างตรงไปตรงมา ทางเลือกหนึ่งคือใช้ชิป23K256หนึ่งตัวหรือมากกว่า พวกเขาเข้าถึงได้ผ่าน SPI และมีห้องสมุด SpiRAMเพื่อช่วยให้คุณใช้งานได้ เพียงแค่ระวังว่าพวกเขาทำงานที่ 3.3V ไม่ใช่ 5V!

หากคุณกำลังใช้เมกะคุณอีกทางเลือกหนึ่งอาจจะได้รับโล่ขยายตัว SRAM จากลากรองจ์จุดหรือวงจรที่มีความทนทาน


1
นอกจากนี้คุณยังสามารถเก็บข้อมูลคงที่ในหน่วยความจำของโปรแกรมแทน SRAM หากคุณมีปัญหาพื้นที่ SRAM และหน่วยความจำโปรแกรมฟรี ดูที่นี่หรือที่นี่
Connor Wolf

1
อีกหนึ่งทางเลือกที่ยอดเยี่ยมสำหรับ EEPROM คือการ์ด SD ใช้เวลาเพียงไม่กี่พอร์ต IO แต่ถ้าคุณต้องการพื้นที่ขนาดใหญ่สำหรับพูดข้อมูลแผนที่หรือสิ่งที่คล้ายกันคุณสามารถสลับและแก้ไขด้วยโปรแกรมที่กำหนดเองบนพีซีได้ง่าย
เพนกวินที่ไม่เปิดเผยตัว

1
ไม่ควรสนับสนุนให้คนใช้ SPI SRAM หรือการขยาย RAM หากหน่วยความจำเหลือน้อย นั่นเป็นเพียงการเสียเงิน การเลือก MCU ที่ใหญ่กว่าจะถูกกว่า นอกจากนี้ประสิทธิภาพอาจแย่มาก ก่อนอื่นคุณควรทำการประเมิน ballpark: หากการใช้ RAM โดยประมาณใกล้เกินขีด จำกัด คุณจะต้องเลือกแพลตฟอร์มบอร์ด / ไมโครคอนโทรลเลอร์ / การพัฒนาที่ผิด แน่นอนว่าการใช้งานที่ดี (การจัดเก็บสตริงในแฟลช) และการเพิ่มประสิทธิภาพ (หลีกเลี่ยงการใช้ไลบรารีบางอย่าง) อาจเป็นตัวเปลี่ยนเกมที่แท้จริง อย่างไรก็ตาม ณ จุดนี้ฉันไม่เห็นประโยชน์ของการใช้แพลตฟอร์มซอฟต์แวร์ Arduino
next-hack

24

เมื่อคุณอัปโหลดรหัสของคุณไปยัง Arduino พูดว่า Uno เป็นตัวอย่างมันจะบอกคุณว่ามีกี่ไบต์ที่ใช้เกิน 32K ที่มีอยู่ นั่นคือจำนวนหน่วยความจำแฟลชที่คุณมี (คิดว่าฮาร์ดดิสก์ของคอมพิวเตอร์) ในขณะที่โปรแกรมของคุณกำลังทำงานอยู่มันกำลังใช้สิ่งที่เรียกว่า SRAM และมีให้ใช้งานน้อยกว่ามาก

บางครั้งคุณจะสังเกตเห็นว่าโปรแกรมของคุณทำงานผิดปกติในจุดที่คุณไม่ได้แตะต้องเลย อาจเป็นไปได้ว่าการเปลี่ยนแปลงล่าสุดของคุณทำให้หน่วยความจำหมด (SRAM) ต่อไปนี้เป็นเคล็ดลับเกี่ยวกับวิธีเพิ่ม SRAM

การจัดเก็บสตริงใน Flash แทน SRAM

สิ่งที่พบบ่อยที่สุดอย่างหนึ่งที่ฉันเห็นคือชิปมีหน่วยความจำไม่เพียงพอเนื่องจากมีสายยาวมากเกินไป

ใช้F()ฟังก์ชั่นเมื่อใช้สตริงเพื่อเก็บไว้ใน Flash แทน SRAM เนื่องจากคุณมีมากกว่านั้น

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

ใช้ประเภทข้อมูลที่ถูกต้อง

คุณสามารถบันทึกไบต์โดยสลับจากint(2 ไบต์) เป็นbyte(1 ไบต์) ไบต์ที่ไม่ได้ลงชื่อจะให้ 0-255 ดังนั้นหากคุณมีตัวเลขที่ไม่สูงกว่า 255 ให้บันทึกไบต์!

ฉันจะรู้ได้อย่างไรว่าฉันมีหน่วยความจำไม่เพียงพอ

โดยปกติคุณจะสังเกตว่าโปรแกรมของคุณมีพฤติกรรมแปลก ๆ และสงสัยว่าเกิดอะไรขึ้น ... คุณไม่ได้เปลี่ยนแปลงอะไรเลยในโค้ดใกล้กับจุดที่มันเกิดความวุ่นวาย หน่วยความจำไม่เพียงพอ

มีฟังก์ชั่นสองสามอย่างที่จะบอกคุณว่าคุณมีหน่วยความจำเท่าใด

หน่วยความจำที่มีอยู่


คุณรู้หรือไม่ว่าF()สิ่งนี้เป็นฟังก์ชั่นเฉพาะของ Arduino หรืออยู่ในไลบรารี AVR? คุณสามารถพิจารณาพูดถึงPROGMEM const ...ด้วย
jippie

นอกจากนี้คุณสามารถใช้โครงสร้างบิตเพื่อลดพื้นที่ใช้งานโดยตัวแปรของคุณ 5eg หากคุณจัดการกับบูลีนจำนวนมาก)
jfpoilpret

17

นอกจากสิ่งที่คนอื่นพูด (ซึ่งฉันเห็นด้วยอย่างเต็มที่) ฉันจะแนะนำให้อ่านบทความ adafruit นี้เกี่ยวกับความทรงจำ มันเขียนได้ดีอธิบายสิ่งต่าง ๆ มากมายเกี่ยวกับหน่วยความจำและให้คำแนะนำเกี่ยวกับวิธีเพิ่มประสิทธิภาพ

ในตอนท้ายของการอ่านฉันคิดว่าคุณจะได้รับคำตอบที่สมบูรณ์สำหรับคำถามของคุณ

ในการสรุปผลคุณมี 2 เป้าหมายการเพิ่มประสิทธิภาพที่เป็นไปได้

  • Flash (เช่นหน่วยความจำโปรแกรม); สำหรับสิ่งนี้คุณสามารถ:
    • ลบรหัสที่ตายแล้ว (เช่นรหัสใด ๆ ที่รวมอยู่ แต่ไม่ได้ใช้) และตัวแปรที่ไม่ได้ใช้ (ซึ่งยังช่วยด้วย SRAM)
    • แยกตัวประกอบของรหัสซ้ำ
    • ลบ bootloader ทั้งหมด (คุณสามารถรับได้ระหว่าง 0.5K สำหรับ UNO และ 2 หรือ 4K สำหรับ Arduino รุ่นอื่น ๆ ); สิ่งนี้มีข้อเสียอยู่บ้าง
  • SRAM (เช่นสแต็กกองและข้อมูลคงที่); สำหรับสิ่งนี้คุณสามารถ:
    • ลบตัวแปรที่ไม่ได้ใช้
    • ปรับขนาดของแต่ละตัวแปรให้เหมาะสม (เช่นอย่าใช้ความยาว -4 ไบต์ - หากคุณต้องการเพียง int -2 ไบต์)
    • ใช้ขอบเขตที่เหมาะสมสำหรับตัวแปรของคุณ (และต้องการสแต็กเป็นข้อมูลสแตติกเมื่อเป็นไปได้)
    • ลดขนาดบัฟเฟอร์ให้น้อยที่สุด
    • ย้ายข้อมูลคงที่ไปที่ PROGMEM (เช่นข้อมูลสแตติกของคุณจะยังคงอยู่ในหน่วยความจำแฟลชและจะไม่ถูกคัดลอกไปยัง SRAM เมื่อเริ่มต้นโปรแกรม) ที่ใช้กับสตริงคงที่ซึ่งคุณสามารถใช้F()แมโครได้)
    • หลีกเลี่ยงการจัดสรรแบบไดนามิกหากไม่จำเป็นจริงๆ คุณจะหลีกเลี่ยงฮีปที่กระจัดกระจายซึ่งอาจไม่หดตัวแม้หลังจากพ้นหน่วยความจำแล้ว

วิธีการเพิ่มเติมเพื่อลดการใช้ SRAM ยังได้อธิบายไว้ด้วย (แต่ไม่ค่อยได้ใช้เนื่องจากค่อนข้างหนักเมื่อการเข้ารหัสและไม่มีประสิทธิภาพมาก) ประกอบด้วยการใช้ EEPROM เพื่อเก็บข้อมูลที่โปรแกรมของคุณสร้างขึ้น แต่ไม่ได้ใช้จนกระทั่งในภายหลังเมื่อเงื่อนไขบางอย่าง เกิดขึ้นเมื่อสามารถโหลดข้อมูลกลับจาก EEPROM


1
การลบรหัสที่ตายแล้ว - คอมไพเลอร์นั้นดีมากเกี่ยวกับการจัดการกับคุณ - มันจะไม่สร้างความแตกต่างถ้าคุณมีรหัสจำนวนมากที่ไม่เคยเรียก หากคุณเผลอโทรไปที่รหัสที่คุณไม่ต้องการก็จะแตกต่างกันแน่นอน
dethSwatch

9

มีสองสิ่งที่ต้องทำถ้าคุณใช้พื้นที่เก็บข้อมูลไม่เพียงพอ:

  • อย่างใด "เพิ่มประสิทธิภาพ" รหัสของคุณเพื่อให้ต้องการพื้นที่เก็บข้อมูลน้อย หรืออย่างน้อยก็ใช้พื้นที่เก็บข้อมูลบางประเภทที่คุณใช้หมด (และใช้พื้นที่เก็บข้อมูลประเภทอื่นที่คุณยังมีเหลืออยู่มาก) หรือ,
  • เพิ่มที่เก็บข้อมูลเพิ่มเติม

มีเคล็ดลับออนไลน์มากมายเกี่ยวกับวิธีการทำสิ่งแรก (และสำหรับสิ่งที่คนส่วนใหญ่ทำกับ Arduino, ที่เก็บข้อมูลในตัวนั้นมากเกินพอหลังจาก "เพิ่มประสิทธิภาพ") ดังนั้นฉันจะมุ่งเน้นไปที่สอง:

มี 3 สิ่งที่ใช้แฟลชหรือ SRAM; แต่ละคนต้องการแนวทางที่แตกต่างกันเล็กน้อยในการเพิ่มที่เก็บข้อมูล:

  • พื้นที่เก็บตัวแปร: เป็นไปได้ที่จะขยาย SRAM เนื่องจาก sachleen ได้ชี้ไปแล้ว SRAM, FRAM และ NVSRAMเหมาะสำหรับตัวแปรที่เปลี่ยนแปลงอย่างรวดเร็ว (โดยหลักการแล้วคุณสามารถใช้แฟลชเพื่อเก็บตัวแปรแล้วคุณต้องกังวลเกี่ยวกับการสึกหรอของแฟลช) SPI (โปรโตคอลอนุกรม) เป็นวิธีที่ง่ายที่สุดในการเชื่อมต่อกับ Arduino ห้องสมุดคอยล์ทำงานร่วมกับไมโครชิพ23K256ชิป SRAM อนุกรม ชิปFRAM อนุกรม Ramtron FM25W256 (ตอนนี้ Cypress เป็นเจ้าของ) ยังใช้ SPI Cypress CY14B101 NVSRAMยังใช้ SPI เป็นต้น

  • ข้อมูลคงที่ที่จะต้องมีในครั้งต่อไปที่เปิดเครื่อง: เกือบจะง่ายเหมือนการขยาย SRAM มีอุปกรณ์เก็บข้อมูลภายนอกEEPROM, FRAM, NVSRAM และ FLASHจำนวนมาก ปัจจุบันต้นทุนต่อเมกะไบต์ที่ต่ำที่สุดคือแฟลชการ์ด SD (ซึ่งสามารถเข้าถึงได้ผ่าน SPI) Ramtron FM25W256 (ดูด้านบน) Cypress CY14B101 (ดูด้านบน) และอื่น ๆ ยังสามารถเก็บข้อมูลคงที่ได้ แผ่นป้องกันการขยายตัวหลายตัวมีช่องเสียบการ์ด SD และห้องสมุดและแบบฝึกหัดหลายตัวรองรับการอ่านและเขียนการ์ด SD (แฟลช) (เราไม่สามารถใช้ SRAM สำหรับสิ่งนี้ได้เพราะ SRAM จะลืมทุกอย่างเมื่อไฟฟ้าดับ)

  • รหัสที่ใช้งานได้: แต่น่าเสียดายที่การขยายหน่วยความจำแฟลชของ Arduino เพื่อเพิ่มพื้นที่โปรแกรมไม่สามารถทำได้ อย่างไรก็ตามโปรแกรมเมอร์สามารถ refactor ร่างเพื่อลดขนาดรหัสที่ค่าใช้จ่ายในการเพิ่มขนาดข้อมูลและทำให้มันทำงานช้าลงเล็กน้อย (ในทางทฤษฎีคุณสามารถแปลร่างทั้งหมดเป็นภาษาที่แปลแล้วเก็บร่างภาพร่างของคุณลงในการ์ด SD แล้วเขียนล่ามสำหรับภาษานั้นที่ทำงานบน Arduino เพื่อดึงและดำเนินการคำแนะนำจาก การ์ด SD - ออกมาใน Arduinoล่ามพื้นฐาน, ล่าม Tom Napier Picaro, บางภาษาเฉพาะแอปพลิเคชัน ฯลฯ )

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.