באג של חמישה למיליון

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

מתאם USB ל-RS485
מתאם USB ל-RS485

את תקן RS485 לתקשורת קווית הצגתי כאן בבלוג לפני ארבע שנים כמעט. לפני זמן-מה קיבלתי פרויקט קטן, שדרש תקשורת כזו בין מערכת Embedded לבין מחשב. הלקוח סיפק לי גם מתאם USB ל-RS485, מתוצרת סין, שמופיע בתמונה למעלה. לא כל כך במפתיע, מערכת ההפעלה Windows 10 סירבה להכיר בקיומו, וזאת כיוון שיש בפנים – כמו בהרבה לוחות ארדואינו Duemilanove ישנים, דרך אגב – שבב מזויף שמתחזה לתוצרת של חברת Prolific. עם זאת, לא היה קשה למצוא דרייבר ישן להתקנה ידנית, ואז הכול עבד בלי שום תקלה.

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

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

החשוד הבא היה הג'וק שממיר אותות RS485 ל-UART, כמו זה שהצגתי בפוסט שבקישור למעלה. הלוג'יק אנלייזר הסיני הראה תוצאות מוזרות ביותר ביציאה של הג'וק – פולס של ביט בודד לכל בייט שנשלח, שזה אפילו פחות ממה שהמיקרו-בקר ראה. הסקופ הראה אות הגיוני יותר, אבל עם תנודות לא מוסברות בזמן "מנוחה". לא הצלחתי להבין מה כל זה אומר, אז ליתר ביטחון החלטתי לנסות להחליף את הג'וק בג'וק מדגם דומה שהיה לי במקרה בהישג יד. כדי לוודא שהג'וק החלופי תקין, חיברתי אותו קודם כול ללוח ארדואינו ויצרתי ככה מתאם USB-to-RS485 מאולתר:

מתאם USB-to-RS485 מאולתר
מתאם USB-to-RS485 מאולתר

המתאם עבד מעולה, אז סימן שהג'וק תקין ואפשר להלחים אותו ללוח. עשיתי את זה – והתקלה חזרה בדיוק כמו קודם. מה עושים עכשיו?

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

האופי המוזר של הזחת הביטים נתן כיוון די ברור: מכיוון שבשידור UART טיפוסי הביטים הנמוכים משודרים ראשונים, ובסיום הבייט יש את ה-Stop Bit שמוודא שהקו חוזר לברירת המחדל HIGH, נראה שהביט הראשון מתפספס איכשהו, והמיקרו-בקר קורא בטעות רק את שבעת הביטים הבאים ואז את ה-HIGH שבסיומם. ומה יכול לגרום לזה? לא סטיית שעון במיקרו-בקר, אחרת גם השידור בכיוון השני היה משתבש, וידעתי שהוא בסדר.

חזרתי לסקופ והסתכלתי שוב מקרוב ובתשומת לב על הסיגנל, בניסיון להבין למה הקריאה גולשת אל ה-Stop bit. ואז, סוף כל סוף, הבחנתי במשהו חריג: ה-Start Bit (זה שמוריד את הקו ל-LOW ומבשר על התחלה של בייט מידע) היה קצר יותר מהביטים האחרים.

במהירות שידור של 115200 ביטים לשנייה, כל ביט נמשך 8.68 מיליוניות השנייה. כדי לקרוא את הנתונים בצורה אופטימלית, המקלט מנסה "לתפוס" כל ביט נתונים בדיוק באמצע. הוא יחכה עד לסיום ה-Start bit, ואז עוד מחצית ממשך הביט (סה"כ 13.02 מיליוניות השנייה), עד לדגימה הראשונה – ואז יבצע עוד שבע דגימות במרווחים של 8.68 מיליוניות השנייה.

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

למה זה לא הפריע לי בפרויקט הקודם? התשובה פשוטה מאד, בדיעבד: כי שם עבדתי במהירות שידור של 9600 ביטים לשנייה (104.16 מיליוניות השנייה לביט), ובסדרי גודל כאלה, להפרש של 5 מיליוניות השנייה אין השפעה. ולמה הלוג'יק אנלייזר הראה לי תוצאות משונות? כי ניסיתי להחזיק ביד את קצה החוט שייצור מגע עם רגל זעירה של ג'וק במארז SOIC, והמגע כנראה לא היה מספיק טוב!

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

מתאם USB-to-RS485 רציני יותר, תוצרת בית
מתאם USB-to-RS485 רציני יותר, תוצרת בית

הבסיס הוא ארדואינו Mega, כי היה צורך בשני מודולי Serial בחומרה. הלד הקטן (קרוב למצלמה) נותן אינדיקציה למצב שידור, ועם ה-Dip Switches במארז האדום אפשר להגדיר את קצב שידור הביטים. היה חשוב לי שתהיה אפשרות לשנות את הקצב בחומרה, וזאת כדי שלא איאלץ לצרוב קוד חדש כל פעם למגה, או להמציא כל מיני פרוטוקולים משונים ש"ירכבו" על השידור הרגיל ויפריעו לו.

עם המתאם החדש הבעיה נפתרה. ה-Start bit היה באורך הנכון, והנתונים זרמו הלוך ושוב בלי הפרעה ובלי שיבושים. אפשר להמשיך בפרויקט!

 

 

כתיבת תגובה

האימייל לא יוצג באתר. שדות החובה מסומנים *