לעולם אל תאמר לעולם לא

לעתים נדירות אפשר, ואפילו צריך, לשבור גם את הכללים המקודשים ביותר בכתיבת קוד – כמו למשל הכללים לבניה נכונה של פונקציות פסיקה. הנה דוגמה מהחיים.

לפני זמן מה עבדתי על פרויקט, שכלל תקשורת בתקן I2C בין ארדואינו לבין מיקרו-בקר ממשפחת PIC. בצד הארדואינו (שהיה כאן ה-Master ולא היה צריך לעשות באותו זמן שום דבר חשוב אחר) אפשר להשתמש בספריית Wire הנוחה, אבל ל-PIC אין ספריה סטנדרטית כזו כך שכתבתי את כל הקוד שלו לבד, עם פניות ישירות לרגיסטרים.

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

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

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

במאמר מוסגר, ספציפית ב-PIC יש מכשול קטן בפני העקרונות הנשגבים האלה: כל הפסיקות השונות "מתנקזות" לווקטור פסיקה אחד ויחיד. במיקרו-בקרים ממשפחת AVR, למשל, לכל פסיקה יש ווקטור (הפניה לפונקציה) נפרד, כך שאפשר לנהל את הפסיקות השונות בצורה נוחה; ב-PIC (לפחות בדגמי ה-Mid-range) אנחנו נזרקים תמיד לתוך אותה פונקציה, ואם אנחנו משתמשים ביותר מסוג פסיקה אחד, עלינו לבדוק בקוד של הפונקציה מי עורר אותה הפעם. לכן, ככל שיש לנו יותר סוגי פסיקות פעילים, כך פונקציית הפסיקה תהיה בהכרח גדולה ומורכבת יותר.

המשכתי בכתיבת הקוד שלי בהתאם לעקרונות המקובלים – הרמת דגלים במקום עיבוד מתוך הפסיקה – והפעלתי את התוכנה. היא עבדה… ונתקעה בכל פעם אחרי מספר שניות.

הסיבה לכך התבררה בקלות. תקשורת I2C היא מהירה יחסית, ותלויה באות שעון שמגיע מה-Master, כך שאין למיקרו-בקר הרבה זמן להגיב. מרגע שהעברתי את הטיפול בתקשורת לקוד הראשי, אפילו עיכוב זניח יחסית כמו מספר קריאות מתחים דרך ה-ADC עלול ליפול על חלון זמן קריטי, לגרום לפספוס של ביט או אות שעון אחד ולשבש  את כל התקשורת. כדי להבטיח שזה לא יקרה, ה-Code Configurator שבר את הכללים וקרא לפונקציות נוספות ישירות מתוך פונקציית הפסיקה.

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

להרשמה
הודע לי על
0 Comments
Inline Feedbacks
הראה את כל התגובות