במוקדם או במאוחר, כל מי שמשחק עם מיקרו-קונטרולרים כמו הארדואינו, PIC או ה-MSP430 נתקל בבעיית הזיכרון: מקום האחסון שעל השבב הראשי אינו מספיק עבור יישום מסוים שאנחנו רוצים ליצור. מה עושים?
אפשרות אחת היא להשיג שבב מאותה משפחה, רק עם יותר זכרון פנימי. זה עלול להיות יקר, ורוב הכסף יילך על יכולות שאנחנו לא באמת צריכים. כמו כן, גם לשבב החדש לא תהיה יכולת הרחבת זיכרון, כך שבשלב כזה או אחר גם הוא לא יספיק.
האפשרות השניה היא להוסיף למעגל רכיבי זיכרון ייעודיים – מעגלים משולבים ("ג'וקים") שכל תפקידם לאחסן מידע בזיכרון גישה אקראית (RAM). אין לי שום כוונה או סיכוי לכסות את התחום הרחב הזה, או אפילו להתחיל לנסות לעשות זאת בפוסט אחד בלבד. במקום זאת, פשוט אציג רכיב זיכרון מסוים שהגיע אליי בדואר אחרי הצהריים – ובאותו ערב כבר שמר עבור הארדואינו בייטים למכביר.
אנחנו מדברים על רכיב בשם 23K256 של חברת Microchip. זהו ג'וק קטן בעל שמונה רגליים בלבד, מותאם למהירות שעון מרבית של 20 מגהרץ, שמחזיק בתוכו 32 קילובייט של נתונים. מה שמייחד אותו מרוב רכיבי הזיכרון שיש (למיטב ידיעתי) בשוק הוא שזהו רכיב סריאלי, כלומר מעביר את הנתונים ביט אחרי ביט, ולא מקבילי. מצד אחד, זה חוסך המון חיבורים לארדואינו – ומצד שני מחייב קצת יותר השקעה בתכנות.
ג'וק זה תואם לתקן SPI, שיטת תקשורת בסיסית בין רכיבים, אבל לא היה צורך להתעמק בפרוטוקול: את כל המידע שהיה דרוש לי לתקשורת ראשונית עם הג'וק לקחתי ישירות מהמפרט הטכני שלו. מדוע לא השתמשתי בספריית SPI של ארדואינו? בעיקר כדי להתנסות מכלי ראשון בתקשורת עם השבב.
שתיים מרגלי הג'וק הן עבור המתח החשמלי (חשוב לשים לב – עד 4.5 וולט לכל היותר! לא לחבר ליציאת 5V של הארדואינו!) והאדמה. יש לו כניסת נתונים אחת ויציאת נתונים אחת, כניסת שעון, כניסת "בורר שבב" (Chip Select – CS) וכניסת "המתנה" (Hold) שאינה חיונית. מה עם הרגל השמינית? NC, כלומר No Connection. סדר הפעולות המינימלי פשוט מאד:
- מורידים את המתח מרגל CS כדי להודיע לשבב שהתקשורת מתחילה
- תוך כדי "תקתוק" של השעון, משדרים לשבב ביט אחרי ביט אחת משתי פקודות – קריאה או כתיבה (כל אחת היא בייט יחיד, מוגדר מראש)
- עדיין בתקתוק, משדרים את ששה-עשר הביטים של כתובת הבייט הרצויה. הג'וק מתעלם מהביט הראשון, מה שמשאיר 32,768 כתובות בעלות משמעות (0-32,767)
- כעת, כמובן תוך כדי תקתוק, מפמפמים פנימה את בייט הנתונים דרך הכניסה או קוראים את הבייט דרך היציאה, בהתאם לפקודה שנתנו קודם
- מעלים שוב את המתח ב-CS כדי להודיע לשבב שזהו, הפעולה הנוכחית הסתיימה.
המימוש של הפרוצדורה הזו קצת פחות טריוויאלי, מכיוון שהביטים נשלחים מהחשוב ביותר (MSB) לפחות חשוב (LSB), וצריך להתחשב בסידור הבייטים בתוך משתנים מסוג int שמשמשים לכתובות. אף על פי כן, מדובר בסך הכל בקוד פשוט, וכעת יש לנו 32 קילובייטים שלמים בגישה מהירה, לאחסון מדידות לאורך זמן, תוצאות חישובים ועוד. עם קצת מאמץ אפשר לשרשר מספר רכיבים כאלה ולהגדיל את הזכרון כמה שרק רוצים.
בעתיד, מן הסתם, אשכלל את הפונקציות כך שיכסו את מלוא היכולות של השבב ואולי אף אצור מהן ספריה. בינתיים, הנה לכם הקוד, וסרטון שלו עם הג'וק בפעולה:
לא ציינת איך הורדת את המתח מ-5 וולט למתח של 4.5 וולט?
או שסיפקת לו 3.3 וולט.
כמו שציינתי קודם חבל שאין שרטוט.
שרטוט לא רלוונטי כאן – זה לא מדריך לחיבור רכיב הזיכרון ספציפית לארדואינו נאנו. הקוד מכיל את הגדרות הפינים הרלוונטיות, ואת אספקת החשמל תביא מאיפה שאתה רוצה. בתמונה למעלה, הפלוס (החוט האדום) חובר לפין 3V3 של הנאנו, שאכן נותן 3.3V.
[עריכה: נכתב כתגובה ל-https://www.idogendel.com/whitebyte/archives/207#comment-59 -עידו]
מערכת הפעלה…
זאת אומרת תוכנה שתנהל את הזיכרון עצמו, ותדע להעתיק קטעי קוד של תוכניות אחרות משבבי זכרון אל המעבד. זה נראה לי מסובך בטירוף, אבל ככה פועל מחשב, לא?
לא התכוונתי לרמה כזו של מורכבות. ברמה הבסיסית ביותר, אתה יכול להגדיר כמה מספרים שייצגו פקודות או פעולות נפוצות (סתם לדוגמה, "בדוק את הקלט מחיישן X ושים את התוצאה במשתנה Y") – ובתוכנה הראשית שלך להגדיר פקודת switch שתדע לקחת כל אחד מהמספרים האלה ולממש את הפקודה שהוא מייצג.
השאלה הנכונה היא מה ישמור את רצף הפקודות על הזיכרון החיצוני מלכתחילה 😉
קוד מפחיד אותי ואני לא באמת מבין עד הסוף את מה שאתה כותב, כמו כן לא נראה לי שאיישם דבר בעתיד הקרוב. אבל בכל זאת אני ממש נהנה לקרוא את הבלוג, מחכים במה שאפשר ומחכה לפוסט הבא בקוצר רוח.
תודה
בכוונה לא סימנתי את הפוסט הזה כפוסט למתחילים… 🙂
תודה. הבלוג עוסק בינתיים בעיקר בארדואינו כי בזה אני מתעסק כרגע, אבל בעתיד יהיה כאן חומר גם על תכנות, ואולי אפילו תכנות למתחילים – ואז אני אצפה להשתתפות מלאה! בעיקר לאור העובדה שתכנות יכול להיות אומנותי לא פחות מכל אומנות אחרת 😉
מה קורה אם התוכנה עצמה גדולה מדי בשביל הזכרון של הארדואינו?
גודל התוכנה הוא בהחלט עניין קריטי מספיק כדי להצדיק שבב חזק יותר, אם כי תמיד יש אלטרנטיבות:
– לכתוב קוד יעיל יותר ולהשיג קומפיילר חכם יותר
– לחלק את הפונקציונליות על פני מספר מיקרו-בקרים, מעגלי משנה וכו'
– ליצור מפענח פקודות מינימליסטי שיוכל לקרוא ולבצע סדרה של פקודות פשוטות מהזכרון
– למישהו יש עוד רעיונות?