אופטימיזציה - צמצום השימוש ב-RAM

כמות זיכרון ה-RAM הפנימי במיקרובקרים, קטנה יחסית. אפילו במקרים שהיישום כולל RAM חיצוני נוסף, אם לא מפתחים את הקוד, בצורה "מודעת" לניצול ה-RAM, קל מאד להגיע למצב, בו נגמר המקום בזיכרון. הטיפים להלן, יעזרו לכן להקטין את השימוש ב-RAM, תוך כדי כתיבת התוכנית, כדי שלא תגיעו לנקודה, שבה תאלצו לערוך "צימצומים בקוד", כדי לאפשר את פעולת המערכת.

 

איפה השארתי את המשתנה שלי?

 

הצרכנים המרכזיים של זיכרון RAM הם:

  • אלמנטים הזקוקים לזיכרון מעצם הגדרתם, כגון משתנים,רגיסטרים ומערכים.
  • המחסנית (Stack).
  • מידע זמני שמאוחסן בזיכרון, כגון חוצץ (Buffer) עבור נתונים המגיעים בתקשורת טורית, או קריאות מחיישנים שונים.

כל עוד התוכנית שלכם משתמשת בנתונים דינמיים (משתנים), אין דרך לבטל לגמרי את השימוש ב-RAM, אך ישנן דרכים מגוונות לצמצם אותו. להלן מספר הצעות יעילות שיאפשרו לכם להקל את העומס על ה-RAM:

  • תשתמשו תמיד במשתנים מהטיפוס (Type) שמתאים לערך שיאוחסן בהם, ולא בטיפוס שאתם "רגילים להשתמש בו". כלומר, אם אתם צריכים משתנה שיחזיק ערכים חיוביים בין 0 ל-255, אל תגדירו אותו מטיפוס short או int אלא קבעו אותו כ-unsigned char. זה חשוב במיוחד, במיקרובקרים שעובדים ב-8 ביט.
  • צמצמו למינימום את השימוש בפונקציות מקוננות (פונקציה שקוראת לפונקציה אחרת שקוראת לפונקציה..). זה ימנע את העמסת המחסנית, שצריכה להחזיק את כתובת החזרה מכל פונקציה שנקראת וגם במימושים מסויימים, להחזיק את הפרמטרים שמועברים מפונקציה לפונקציה.
  • המנעו משימוש במשתנים גלובליים. הם מחזיקים מקום בזיכרון, מתחילת התוכנית ועד סופה. אפילו אם השתמשתם בהם רק פעם אחת, בתחילת התוכנית.
  • תשתדלו ככל שניתן, להשתמש במשתנים לוקליים ולהמנע משימוש במשתנים סטטייים. המקום בזיכרון המוקצה למשתנים לוקליים, מתפנה בסיום השימוש בהם, והקומפיילר יכול להשתמש בו שוב. הזיכרון בו מאוחסנים משתנים סטטיים (בדומה למשתנים גלובליים), אינו מתפנה עד לסיום ריצת הקוד, גם בזמנים בהם לא נעשה שימוש במשתנה.
  • אם ניתן, המנעו משימוש בהקצאות דינמיות ותשתמשו רק בהקצאות RAM סטטיות. קל יותר לקומפיילר לבצע אופטימיזציה על הקצאות סטטיות.
  • אם בקוד ישנם ערכים קבועים, לעולם אל תציבו אותם במשתנים רגילים. הדרך הנכונה היא להגדיר אותם כ-const. הגדרה כזו, מאפשרת לקומפיילר לאחסן את הערכים ב-ROM ולא ב-RAM.
  • תשתדלו שלא להעביר הרבה ארגומנטים אל פונקציה (מקסימום 3). כי במקרים מסויימים, זה יוצר שימוש מוגבר ב-RAM (התוצאה הפרקטית, תלויה במיקרובקר ובקומפיילר בהם אתם משתמשים).
  • אל תעבירו מבנים (struct) גדולים אל פונקציות, לפי ערך (by value). זה מבזבז RAM וגם איטי יחסית, כי מבוצעת העתקה ממקום אחד בזיכרון למקום אחר. מבנים יש להעביר לפונקציה לפי ייחוס (By reference), כלומר, שילחו לפונקציה רק מצביע אל המבנה הרצוי.
  • פונקציות שאינן מחזירות ערך, יש להגדיר כטיפוס void. אם לא תציינו זאת בפירוש, הקומפיילר יקבע את טיפוס הפונקציה לפי ברירת-המחדל שלו ובהתאם גם יוקצה רגיסטר או מקום בזיכרון שמיועדים להחזרת ערך מהפונקציה. זהו בזבוז.
  • תשתדלו להמנע ממצב של פסיקות מקוננות (פסיקה שמתקבלת בתוך פסיקה אחרת). מכיוון שלרוב, קוד טיפול בפסיקה (ISR), שומר משתנים ב-RAM או במחסנית (שגם היא ב-RAM), ואז קינון הפסיקות עלול להעמיס את הזיכרון.

שימוש מחושב וזהיר במשאבים של המיקרובקר, יאפשר לכם לכתוב מימושים מלאים ומורכבים יותר, אפילו במקרים בהם המשאבים דלים ובמבט ראשון נראה, שהם לא יספיקו לביצוע מושלם של המשימות.