facebook pixel בלוג: האם אנחנו מתכנתים נכון עם הארדואינו? - חלק 2 - www.4project.co.il
Main logo www.4project.co.il
כל הרכיבים לפרוייקט שלכם
עגלת קניות

העגלה ריקה

האם אנחנו מתכנתים נכון עם הארדואינו? - חלק 2


2024-06-27 14:45:28
זהו המשך של הפוסט הקודם - האם אנחנו מתכנתים נכון עם הארדואינו?

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

בפוסט אחר סיפרתי לכם על סביבת ה-EBF שהתחלתי לפתח, ואני ממשיך עם הרעיון הזה כשיש לי זמן.

מה יהיה פוסט הזה?

  • אספר לכם על מעבר לכרטיס SAMD21 Mini של SparkFun
  • הגעה ל-22uA במצב שינה
  • עוד קיטורים על הספריות הקיימות
  • מטרות הרעיון שמאחורי כל העבודה הזו

המעבר ל-SAMD21

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

ה-SAMD21 הוא ליגה אחרת בהשוואה ל-ATMega328 עליו מבוסס כרטיס ה-UNO. קודם כל הבקר שלו הוא 32bit, בהשוואה ל-8bit של UNO, ובמבנה שלו הוא יותר קרוב למעבד מאשר למיקרובקר. 

יש הרבה טיימרים פנימיים שאפשר לנצל לצרכים שונים, כולם יכולים להעיר את הבקר ממצבי השינה השונים. כל קווי ה-IO גם הם יכולים להעיר את הבקר (בהשוואה ל-2 ב-UNO).

SAMD21 מבוסס על מעבד ARM, כמו רוב המיקרובקרים המודרניים של היום. ובגלל שזה ARM, הם בנויים בצורה מודולרית.
ל-SAMD21 יש 4 מודולי תקשורת, שכל אחד יכול לתפקד כערוץ UART, או SPI, או I2C. וכל מודול תקשורת מחובר ל-2 סטים של קווים, כך שיש גמישות יפה שאפשר לקבל, גם למרות שחלק מהקווים כבר בשימוש לצרכים אחרים על כרטיס הפיתוח.

מודול חשוב נוסף שיש למעבדי ARM זה בקר פסיקות שהיה חסר לי ב-ATMega328. הוא מאפשר לבדוק אילו פסיקות קיימות בכל רגע במערכת, כך שזה מאפשר לטפל בפסיקות בסביבת ה-EBF בצורה קצת יותר אלגנטית.

לקחתי כרטיס SAMD21 Mini של SparkFun למשחקים שלי. יש עוד כרטיסים נחמדים שמבוססים על SAMD21, כמו ה-SAMD21 Micro של SparkFun, או XIAO SAMD21 של SeeedStudio. יש גם את ה-RedBoard Turbo של SparkFun בתצורה של כרטיסי UNO הפופולריים. בחרתי את דגם ה-Mini כי רציתי משהו יחסית קטן, אבל עם מספיק קווים למשחקים.



אם אני זוכר נכון, ה-SAMD21 צץ לחיינו כשהיה מחסור ברכיבי ATMega328 בשוק והכרטיסים מבוססי SAMD21 היו נראים לי כמו מועמד ראוי להחליף את מקומו של ה-UNO העתיק. אבל זה לא קרה. למרות שסביבת ה-Arduino מחביאה את כל המורכבות של המעבד ואפשר לעשות עליו בדיוק את מה שעושים עם ה-UNO. אולי בגלל שהוא יקר יותר, אולי בגלל שהוא פועל על 3.3V וכולם התרגלו ל-5V של ה-UNO... לא יודע... אבל אם מישהו רוצה לעלות מדרגה לעולם המיקרובקרים 32bit משוכללים יותר, זהו ללא ספק אחד המועמדים הטובים.
וכמו שהזכרתי, רוב המיקרובקרים המודרניים מבוססים על ARM, כך שברגע שמבינים איך הם בנויים, כולם נראים די דומים אחד לשני.

בדקתי שכל הפונקציונליות של ה-EBF שכתבתי עובדת על הכרטיס החדש. התאמתי את המחלקה של תקשורת טורית למימוש של SAMD21 (כי יש מימוש שונה של תקשורת Serial. אפילו 2 מימושים ל-SAMD, אחד לתקשורת דרך חיבור ה-USB שלו ואחד למודולי תקשורת הנוספים שיש לבקר). את המימוש של פסיקות השארתי בינתיים בצד כי רציתי לבדוק עד כמה אפשר להוריד את צריכת הזרם של הכרטיס הזה.

להרדים את הכרטיס

הרצתי תוכנית פשוטה שמדליקה לד שיש על הכרטיס במשך 100 מילישניות ומשאירה אותו כבוי במשך 5 שניות.
מדדתי את צריכת הזרם בעזרת מד מתח/זרם בחיבור USB וקיבלתי צריכה של 34mA. זה בתקופות של 5 שניות שהלד לא דולק ובלי שום מצב שינה.

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

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

במצב שינה עמוקה (StandBy) צריכת הזרם ירדה ל-22mA. לא בדקתי, אבל לפי הפורומים השונים יציאה ממצב זה יכולה לקחת כמה מילישניות בגלל שהשעון במצב שינה זה יורד מ-48MHz למתנד פנימי חסכוני במיוחד שרץ הקצב של 32.768kHz, אז כל גישה למודולים הפנימיים של הבקר לוקחת הרבה זמן עד שחוזרים שוב לשעון המהיר.

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

הגיע זמן לאופטימיזציות...

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

כמה מעברים עם סכין יפנית וכבר הורדנו 5mA מצריכת הזרם.

עוד דברים שהיה צריך לשנות לפי המלצות בפורומים שונים, זה לעצור את כל הטיימרים, להשאיר רק טיימר אחד שיעיר את הבקר (השתמשתי בטיימר RTC שהוא טיימר היחיד של 32bit), לנתב את כל המודולים במעבד שלא אמורים לתפקד לשעון שלא רץ (הכל כמו לגו ב-ARM, אפשר לחבר מודולים שונים ביניהם בתצורות שונות). ודבר נוסף שהוריד את הצריכה בצורה יפה זה לבטל את כל קווי ה-IO שלא בשימוש. בקוד האתחול של ארדואינו הם מגדירים את כל הקווים ככניסות דיגיטליות עם נגד PullUp מחובר, ודברים אלה צורכים זרם. באתחול של מודול ה-EBF אני מבטל את ההגדרות האלה.

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

מד המתח/זרם בחיבור USB כבר לא עוזר למצב הזה. חיברתי את הכרטיס לספק שולחני, דרך רב מודד הזה שיש לי מהתקופה שהוא היה נמכר ב-SparkFun שיכול למדוד זרם במיקרו-אמפר:
"רב מודד UNI-T UT60A"

אני רואה שגם הרב מודד הפשוט יותר שיש לנו באתר יכול למדוד זרמים אלה:


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

הייתי סקרן לראות כמה הכרטיס צורך במצב רגיל, בלי שינה, עם כל השינויים שביצעתי (שעונים, ביטול כניסות IO וכו'). היה נחמד לראות צריכה של 11.3mA, פי 3 פחות מהזרם ממנו התחלתי.

הערה:
מאוד יכול להיות שביטלתי יותר מדי דברים ושלא חזרו לפעילות רגילה ואני פשוט עדיין לא רואה את זה. למשל עדיין לא בדקתי אם מערכת הפסיקות עדיין עובדת אחרי שיוצאים ממצב השינה. או האם הבקר באמת רץ ב-48MHz ולא עדיין ב-32KHz. החיווי היחיד שיש לי זה לד שמופעל ל-100mSec כל 5 שניות, מה שאפשר לעשות גם כשהמעבד לא לגמרי ער. כך שמאוד יכול להיות ש-11.3mA זה מספר לא כל כך ריאלי למצב אמיתי.

אז מה עושים עם ה-500uA? כל מה שניסיתי להוסיף לקוד, לכבות עוד מודולים וכו', לא עזר.

החשוד המיידי הוא מייצב מתח AP2112K-3.3V שיש על הכרטיס כדי להמיר את ה-5V בכניסת ה-USB ל-3.3V שהבקר צריך כדי לפעול. אגב, הבקר יכול לעבוד במתחים בין 1.62V ל-3.63V, כך שמי שמספק את המתח ישירות לקו ה-3.3V של הכרטיס יכול להפעיל אותו גם עם מתחים נמוכים יותר.

ניסיתי לספק 3.3V ישירות לקו ה-3.3V של הכרטיס בתקווה שהמייצב לא יצרוך זרם אם לא משתמשים בו, אבל זה לא עזר. SparkFun השתמשו במייצב קצת יותר משוכלל ממה שאפשר למצוא בכרטיסים אחרים, יש לו קו EN שאמור לאפשר את העבודה שלו, או בתקווה לבטל אותו. לפי השרטוט ה-EN מחובר לכניסת VIN של הכרטיס, אז קיוויתי שאולי אם אחבר את VIN לאדמה, אז המייצב יתבטל. חיברתי את ה-VIN דרך נגד 100K לאדמה כי לא ידעתי אם יש שם זרם או לא, וזה לא עזר בכלל. כנראה שבכל זאת יש מעבר זרם דרך המייצב, גם אם הוא לא מאופשר.

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

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

כמה יצא? 22uA! כן, כן... 22 מיקרו-אמפר! עם צריכה כזו הכרטיס הזה יוכל לעבוד על סוללת CR2032 מעל שנה!

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

לפי כל הדוגמאות של ארדואינו (הלא טובות!) צריך לדגום את הטמפרטורה מחיישן כלשהו ולהוסיף ()delay בין הדגימות אם לא צריכים קצב של מאות דגימות בשניה. עם או בלי ()delay בצורה זו הכרטיס יצרוך פי 1500+ יותר זרם ממצב שינה עמוקה שהצלחתי להגיע אליה.

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

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

וזו הדרך הנכונה לעבוד! לא ()delay, לא להתעורר כל הזמן כדי לדגום משהו... וככה כל הדברים מתוכננים לעבוד... כשהטלפון שלכם מונח על השולחן, הוא ישן. לחצתם על איזה שהוא כפתור? נגעתם במסך? הזזתם אותו? הבקר מקבל פסיקה מאחד הרכיבים שיש בטלפון, מתעורר ועושה את מה שצריך לעשות. רק ככה אפשר להגיע למקסימום זמן עבודה של סוללה.

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

חיישן שיוכל לדגום לבד צריך להיות יותר משוכלל מהחיישנים הפשוטים שאנחנו רגילים לראות בפרוייקטי ארדאוינו, אז הלכתי למחלקת חיישנים ממערכת Qwiic של SparkFun כי הרכיבים האלה מתקשרים דרך ערוץ ה-I2C שבשימוש בכל המוצרים המודרניים (כמו הטלפונים שלכם למשל) וגם הייתי צריך רכיב שמתקשר דרך I2C כדי להוסיף מחלקה רלוונטית למערכת ה-EBF. סיננתי את המחלקה כדי לראות רק חיישני טמפרטורה ואני רואה שלכולם יש קו INT (פסיקה), או בחלקם הם קוראים לו ALERT (התרעה). בחרתי את הרכיב הכי זול, שזה חיישן מדגם STTS22H:

לפי המפרט של הרכיב, הוא צורך רק 2uA במצב עבודה של דגימות של שניה:
"צריכת זרם של רכיב STTS22H"

הוא יכול לדגום גם 25 פעם בשניה, 50, 100 ו-200, מה שיצרוך יותר זרם כמובן, אבל יוסיף תגובתיות אם זה קריטי.
למה הצריכה כל כך נמוכה? כי חיישן טמפרטורה STTS22H הוא רכיב חומרתי, שעשו לו כל האופטימיזציות האפשריות כדי להיות אטרקטיבי בהשוואה למוצרים אחרים.
שימו לב שהמפרט מציין שבמצב One-shot, כלומר כשהחיישן ישן עד שהוא מקבל פקודה למדוד, הוא צורך רק 1.75uA! לכל ננו-אמפר יש חשיבות כשפועלים על סוללות!

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

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

ומכאן ישר ל...

עוד קיטורים על הספריות

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

החיישן מתקשר דרך ערוץ ה-I2C, כך שציפיתי שיהיה שימוש באובייקט ה-Wire שסביבת הארדואינו מספקת עבור תקשורת I2C. איזו מחלקת ++C שעוטפת את ההודעות שנשלחות לחיישן, מתרגמת את התוצאה למעלות צלזיוס, פרנהיט וכו'... זה התחיל כך... אבל המחלקה הזו קוראת לפונקציות C שסופקו ע"י ST Microelectronics, יצרן החיישן עצמו. וכדי שהפונקציות יוכלו לגשת לערוץ ה-I2C צריך לספק להם פונקציות כתיבה וקריאה לערוץ, שניגשות לאובייקט שמיוצר משתי מחלקות אחרות שעוטפות את ה-Wire של ארדואינו... למה??? למה צריך את כל הסיבוך הזה?! לחישן הזה יש כולה 6 רגיסטרים, ששניים מהם מחזירים את הטמפרטורה שהוא מודד ונקראים יחד. היה אפשר לגשת לכל הנתונים האלה ישירות מהמחלקה שכתבתם, דרך ה-Wire של ארדואינו...

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

בפונקציית ()setup של הדוגמאות יש שורות אלה:
קוד: בחר הכל
// Other output data rates can be found in the description
// above. To change the ODR or mode, the device must first be
// powered down.
mySTTS.setDataRate(STTS22H_POWER_DOWN);
delay(10);
mySTTS.setDataRate(STTS22H_1Hz);


אתם מספקים ספריה, כנראה למשתמש המתחיל. אתם יודעים שיש מגבלה מסויימת בשימוש, שצריך להעביר את הרכיב למצב POWER_DOWN כדי לשנות את קצב המדידה... למה זה צריך לעניין את המשתמש? למה לא להחביא את זה בתוך הפונקציה שעושה את השינוי של הקצב? אני בטוח שהיו כאלה שלא הסתכלו בדוגמאות, ראו פונקציה ()setDataRate ופשוט קראו לה בלי לעבור דרך POWER_DOWN. מניח שזה עובד לרוב האנשים כי המצב הראשוני של הרכיב הוא POWER_DOWN וכנראה שקובעים את קצב הדגימה רק בזמן האתחול. אבל מי שמשנה את קצב הדגימה תוך כדי ריצה ולא זוכר שצריך לעשות את המעבר הזה, כנראה שנתקל בבעיה...

ואחרי זה יש גם את השורות האלה:
קוד: בחר הכל
// Enables incrementing register behavior for the IC.
// It is not enabled by default as the datsheet states and
// is vital for reading the two temperature registers.
mySTTS.enableAutoIncrement();


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

דוגמה 2 שלהם אמורה להראות איך משתמשים בפסיקה (Interrupt) שהרכיב מספק, כשהמדידה יוצאת מחוץ לטווח המוגדר. שמחתי שסוף סוף מראים למשתמשים איך באמת צריך להשתמש בפסיקות, שזו כאמור הדרך הנכונה ביותר לעבוד עם רכיבים אלה. לכרטיסי Arduino יש קווי פסיקות, כך שציפיתי שיחברו את קו ה-INT של החיישן לאחת מכניסות הדיגיטליות של הבקר, יקראו ל-()attachInterrupt כדי להגדיר את ה-callback function וסוף סוף ינצלו את קו הפסיקה...

ומה אני רואה בקוד של הדוגמה?
קוד: בחר הכל
void loop()
{
    // Checking if data ready is not necessary when output is set higher
    // than 1Hz.
    mySTTS.getTemperatureF(&temp);

    // Temperature in different units can be retrieved
    // using the following functions.

    //mySTTS.getTemperatureC(&temp);
    //mySTTS.getTemperatureK(&temp);

    Serial.print("Temp: ");
    Serial.print(temp);
    Serial.println("F");

    if( digitalRead(tempInterrupt) == LOW )
    {
        Serial.println("Temperature threshold");
        while(1);
    }

    // delay = 1/ODR
    delay(40);
}

אותו קוד בתוך ה-()loop כמו הדוגמה בלי הפסיקה, והשוני היחיד הוא שהם קוראים גם את הערך של הכניסה הדיגיטלית אליה מחובר קו ה-INT של החיישן עם ()digitalRead כדי להבין אם יש אירוע של פסיקה ומדפיסים עוד שורה דרך החיבור הטורי... שוב אכזבה... זה ממש לא שימוש בפסיקות...

לדעתי דרוש שינוי

לאן אני חותר עם כל זה? 

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

לפני כ-14 שנה מנכ"ל SparkFun פרסם את הפוסט הזה, שאומר שהם מוכרים פרווה של יאק כאנלוגיה לביטוי "yak shaving" באנגלית. מה שהוא אומר, זה שלא צריך להתעסק בדברים הקטנים שמישהו כבר עשה כדי להתקדם עם הפרוייקט שלכם. כמו שצוות הארדואינו סיפק לעולם כרטיסים מוכנים לעבודה, בלי הצורך לגלח יאק (לייצר מעגל מודפס, להלחים רכיבי SMD וכו'), כך גם SparkFun ידועים בזה שהם מספקים מודולים של חיישנים ורכיבים אחרים כמוצר מוכן (בלי צורך לתכנן מעגל מודפס ולהלחים רכיבי SMD שאי אפשר להלחים בכלל בצורה ידנית).

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

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

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

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

זה לא מסתכם רק במחברים. רכיבים המודרניים הולכים לכיוון של תקשורת I2C ו-SPI. עבודה במתחים נמוכים יותר מה-5V הפופולרי. צריך להבין "קצת" באלקטרוניקה, שלא מחברים 5V לרכיב שפעול ב-3.3V, צריך להבין האם צריך להשאיר נגדי pull-up על קווי I2C או לא, האם הרכיבים השונים לא מתנגשים עם הכתובת על הערוץ ועוד ניואנסים כאלה ואחרים.

האם אנשים אלה יוכלו להסתדר עם פסיקות ומצבי שינה של מיקרובקר כדי לבנות את המוצר הפשוט כביכול שהזכרתי קודם? כנראה שלא!

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

כל זה מסתכם ל-4 נקודות הבאות:
  1. כדי לעבוד בצורה הנכונה והיעילה עם מיקרובקרים חייבים להשתמש בפסיקות (חסכון בזרם, תגובתיות)
  2. צריך שאפשר יהיה לחבר את הרכיבים בלי הצורך בהלחמה בכלל
  3. להחביא מהמשתמש את כל הנושא של הגדרות החיבור (5V או 3.3V, כתובות המתנגשות של רכיבי I2C, נגדי pull-up וכו')
  4. הצד התוכנתי, Framework שתומך בכל התכונות האלה ומבצע תהליכי זיהוי ומיפוי של הרכיבים המחוברים

נצלול קצת יותר לתוך כל אחת מהנקודות...

עבודה עם פסיקות

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

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

בלי הלחמות

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

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

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

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

למה I2C? כי רוב הרכיבים המודרניים הולכים לכיוון הזה. דה-פקטו זה הסטנדרט היום לתקשורת בין הרכיבים במכשיר הטלפון שלכם ומוצרים רבים אחרים. הרעיון הפשוט הזה להשתמש במחבר קטן ועקבי עבור כל המודולים החדשים שלהם מצא חן בעיני צוות הארדואינו, והם התחילו להוסיף את מחבר ה-QWIIC לחלק מהכרטיסים החדשים שלהם. אפילו המתחרה הגדול שלהם, Adafruit, החליטו להשתמש באותה השיטה במוצרים שלהם, רק שהם קוראים לה חיבור STEMMA. השוני הוא ש-QWIIC הוא רק 3.3V ו-STEMMA מאפשר לבחור בין 3.3V ו-5V. לפי SparkFun, יותר מ-90% מהרכיבים שמופיעים בשוק פועלים ב-3.3V והמגמה מתקדמת לכיוון הזה, כך שאין יותר מדי הגיון לתמוך ב-5V.

מה לגבי פסיקות עם מערכת QWIIC? שימו לב מה SparkFun רושמים בעמוד הבית של QWIIC:
What about the INT pin?
We deliberately chose four conductors to increase usability of the interconnecting cables, minimize the cost of the connectors and limit the PCB footprint. All boards with extra pin options (such as interrupts, address selection, power save mode, etc.) will have those pins broken out to 0.1" holes, so the end user can add extra connections as needed.


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

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

שני הפתרונות, גם GROVE וגם QWIIC/STEMMA מפספסים את הנקודה הראשונה שלי: חייבים להשתמש בפסיקות. ואם רוצים בכל זאת להשתמש בהם, תצטרכו להלחים דברים, כך שזה שובר את הנקודה השניה שלה: בלי הצורך להלחים.

הפתרון לנקודה זו הוא להשתמש במחברים בעלי 5-6 קווים כדי לאפשר תקשורת I2C וגם קו אחד או שניים לפסיקות.

בלי הגדרות חיבור

נעזוב את הנושא של 5V או 3.3V. נניח שהולכים על חיבורי QWIIC כדי לגלח קצת פחות את היאק, כל הרכיבים פועלים ב-3.3V. אשתמש בתמונה היפה מהעמוד הראשי של מערכת QWIIC באתר SparkFun:
"רכיבים מחוברים דרך מחברי QWIIC"

זה נראה כל כך יפה... אבל... 
המשתמש צריך לדעת שצריך לנתק את נגדי ה-pull-up בשלושת המודולים הקרובים למיקרובקר ולהשאיר אותם רק במודול האחרון. שיניתם את הסדר של החיבורים? צריך כנראה להחזיר את החיבור של הנגדים (להלחים) במודול אחד או יותר.

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

כך נראה החלק האחורי של מודול כפתור למערכת QWIIC. הגשרונים ADR נועדו לאפשר לכם לשנות את הכתובת של הרכיב בערוץ ה-I2C. אם אתם רוצים לחבר יותר מכפתור אחד מסוג זה למיקרובר דרך חיבורי QWIIC, חייבים להלחים את הגשרונים כדי לשנות את הכתובת:
"צד האחורי של מודול כפתור QWIIC"

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

אוסיף עוד קצת שמן למדורה... נניח שקראתם במדריך כלשהו שצריך לחבר את קו ה-INT לקו מספר 2 של הבקר...
ראיתם איך נראה מפרט החיבורים של כרטיס ה-SAMD21 Mini של SparkFun? (פתחו את ה-PDF כדי לראות את הגרסה המוגדלת)
"מפרט קווים של כרטיס Mini SAMD21"

אז לאיזה קו מספר 2 הכוונה? D2? PA02? או אולי EXTINT2? כל אחד מהם זה קו אחר...

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

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

אני חושב שאפשר לייצר מערכת Plug-and-Play מלאה, שתחביא את כל הסיבוכיות הזו מהמשתמש.
יש לי כיוון לפתרון של הנושא הזה, אבל הוא כרוך בצורה מלאה בסביבת הפיתוח (Framework) שצריכה להכיר את הרכיבים שמחוברים.
לכל מודול צריכה להיות יכולת להזדהות ולספק את כל הנתונים שהוא מתבסס עליהם, כמו מה כתובת ה-I2C, האם הרכיב תומך בפסיקות וכו'. כל זה אפשר לעשות בעזרת רכיב EEPROM פשוט וזול שישב על אותו קו ה-I2C יחד עם הרכיב שעל המודול.

זה מאוד מזכיר את פתרון ה-Plug-and-Play של שנות ה-90 לכרטיסי הרחבה של המחשבים באותו תקופה. בלי לשנות גשרונים (ולפעמים לחתוך או להלחים חיבורים), הכרטיסים פשוט לא עבדו עם המחשב או התנגשו אחד עם השני. הכרטיסים לא ידעו אם קו הפסיקה פנוי (כן, גם במחשבים הכל עובד עם פסיקות), האם כתובות הזכרון לא מתנגשים עם כרטיס אחר במחשב. נשמע מוכר?

הצד התוכנתי

פתרון ה-Plug-and-Play במחשב לא היה רק חומרתי. מערכת האתחול של המחשב (ה-BIOS) היתה עושה תהליך של Enumeration, זיהוי הכרטיסים שמותקנים במחשב והיה מקצה להם את קווי הפסיקות והכתובות שהם צריכים להשתמש כדי לא להתנגש אחד עם השני. ה-BIOS היה עושה מיפוי של המשאבים של המחשב לצרכים של הכרטיס המותקן.

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

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

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

אני בהחלט רואה איך אפשר לבנות מערכת PnP - Plug-and-Play על בסיס ה-EBF. כבר בקוד הקיים היום האובייקטים נרשמים ל-EBF כשהם נוצרים. להוסיף מנגנון מיפוי זה לא משהו שהוא לא אפשרי. הבעיה היא שאצטרך לכתוב את ה"דרייברים" לכל הרכיבים בעצמי. אולי זה אפילו לטובה, אחרי שהראתי לכם אין נראות הספריות של יצרני הרכיבים Sad emoticon

קוד בסגנון הבא אפשרי וזה פחות או יותר כל מה שיהיה צריך כדי לייצר מערכת שתישן כל הזמן, עד שחיישן הטמפרטורה STTS22H לא יזהה טמפרטורה מעל 40 מעלות, וכשזה יקרה הבקר יבהבה מהר בלד:
קוד: בחר הכל
#include <Arduino.h>
#include "PnP.h"

PnP_Core PnP;

PnP_TemperatureSensor_STTS22H tempSensor;
PnP_StatusLed led;

// Temperature sensor callback
void onTempHigh()
{
    // Temperature crossed the upper limit, blink the led
    led.Blink(200, 200);
}

void setup()
{
    // Initialize PnP framework
    PnP.Init();
    // Enable deep-sleep mode
    PnP.SetSleepMode(PnP_SLEEP_DEEP);

    // Initialize status LED
    led.Init();
    // Initialize temperature sensor
    tempSensor.Init();

    // Set operation mode to 1Hz samples
    tempSensor.SetOperationMode(SAMPLE_1HZ);

    // Set callback to be called when the temperature raises above 40 degC
    tempSensor.SetHighThresholdC(40, onTempHigh);
}

void loop()
{
    // Let PnP framework to do all the processing
    // Your logic should be done in the callback functions
    PnP.Process();
}


אתם לא רואים אתחולים בקוד הזה כי מערכת PnP תוכל לזהות אילו רכיבים מחוברים לערוץ ה-I2C ואילו אובייקטים (tempSensor) מוגדרים בקוד, ותקשר ביניהם.

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

מה אתם אומרים? אשמח לתגובתכם לפוסט בפייסבוק.

הודעות נוספות:

  • בלוג ספריית ה-Event Based Framework

    ספריית ה-Event Based Framework

    2024-06-06 15:04:27

    זהו המשך לפוסט הקודם שלי לגבי תוכנית מסגרת (Framework) שתאפשר לכתוב תוכניות ארדואינו בצורה יעילה (והגיונית) יותר, כמו בסביבות Embedded מקצועיות שאני רגיל.

  • בלוג האם אנחנו מתכנתים נכון עם הארדואינו?

    האם אנחנו מתכנתים נכון עם הארדואינו?

    2024-05-27 13:41:19

    שאלה קצת פילוסופית, וכנראה שיהיו הרבה דעות לכל מני כיוונים בנושא זה, אבל יש לי (ולא רק לי כנראה) בעיה עם הצורה בה כולם מתרגלים לכתוב את הקוד לארדואינו.

  • בלוג כמה עולה לייצר כרטיס Arduino UNO?

    כמה עולה לייצר כרטיס Arduino UNO?

    2024-05-05 12:27:26

    הייתי סקרן לבדוק כמה עולה לייצר כרטיס פופולרי כמו Arduino UNO R3...
    כמובן שאין לי את כל המידע, כמו כמה זמן העבודה מושקע בייצור, עלות שעת עבודה, כמה חשמל צריך כדי לייצר כרטיס, כמה מהכרטיסים יוצאים תקינים (מה שנקרא yield), עלות החומרים השונים כמו בדיל, בלאי של המכונות ועוד הרבה מאוד דברים אחרים... אבל מה שכן אפשר למצוא זה עלות הרכיבים, לפחות כדי לקבל סדרי גודל...

  • בלוג שיפור משמעותי באתר - סינון מוצרים

    שיפור משמעותי באתר - סינון מוצרים

    2024-03-15 14:43:06

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

  • בלוג תוכניות למערכת בית חכם DIY

    תוכניות למערכת בית חכם DIY

    2023-12-17 16:16:30

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