3.29. מצבי צריכת חשמל נמוכה ושינה¶
מצלמות המופעלות מסוללה וחיישנים הפעילים לסירוגין אינם זקוקים לכך שה-CPU יפעל במהירות מלאה כל הזמן. מודול machine חושף ארבעה מצבי חיסכון בחשמל הולכים ומעמיקים – active, idle(), lightsleep(), ו-deepsleep(). כל צעד עמוק יותר מכבה חלק גדול יותר של השבב וחוסך יותר חשמל, במחיר של זמן התעוררות ארוך יותר. בחירת המצב הנכון היא איזון בין כמה חשמל המצלמה חוסכת לבין כמה מהר היא יכולה להגיב כאשר משהו קורה.
3.29.1. Active¶
מצב ברירת המחדל. ה-CPU מריץ Python, כל התקן היקפי מתוזמן בשעון, וצריכת הזרם היא הגבוהה ביותר – עשרות מיליאמפר על מסילת הלוגיקה של המצלמה, בתוספת כל מה שאביזרים מחוברים מושכים דרכה.
3.29.2. idle()¶
machine.idle() משבית את שעון ה-CPU עד שמתרחשת כל פסיקה (התקן היקפי, טיימר, פסיקת פין). ה-RAM פעיל, ההתקנים ההיקפיים נשארים דולקים, השעונים ממשיכים לפעול – רק ה-CPU עצמו מושהה, והוא מתעורר תוך מיקרו-שניות כשיש עבודה לעשות.
השתמשו בו בתוך כל לולאת polling צפופה שממתינה למשהו חיצוני שיקרה:
import machine
while not button_pressed():
machine.idle()
ה-CPU מפסיק לבזבז מחזורים על בדיקת ה-while עצמה ומתעורר באופן טבעי כשהאירוע הבא מגיע – חיסכון קטן שמצטבר לאורך לולאה שרצה מיליוני פעמים.
3.29.3. lightsleep()¶
machine.lightsleep() הוא הצעד הבא מטה. ה-CPU נעצר לחלוטין ורוב השעונים הפנימיים של השבב מכובים, אך ה-RAM ומצב ההתקנים ההיקפיים נשמרים. כשמקור ההתעוררות מופעל, הסקריפט ממשיך בדיוק מהנקודה שבה קרא ל-lightsleep – המשתנים, ה-handles הפתוחים, והנתונים הממתינים כולם תקינים – בסדר גודל של מילי-שניות מאוחר יותר.
import machine
from machine import Pin
wake_pin = Pin("P0", Pin.IN, Pin.PULL_UP)
wake_pin.irq(lambda _: None, trigger=Pin.IRQ_FALLING, wake=machine.SLEEP)
while True:
do_work()
machine.lightsleep() # wakes on a falling edge on P0
מקור ההתעוררות – כאן פסיקת פין – חייב להיות מוגדר לפני קריאת השינה. צריכת החשמל יורדת באופן משמעותי ביחס למצב active; המספר המדויק תלוי בלוח ובאילו התקנים היקפיים עדיין מוגדרים.
3.29.4. deepsleep()¶
machine.deepsleep() הוא המצב העמוק ביותר. ה-CPU נעצר, ההתקנים ההיקפיים מכובים, ותכולת ה-RAM עלולה לאבד. הדברים היחידים שעדיין צורכים חשמל הם מעגל ההתעוררות ומעט לוגיקה תמיד-פעילה.
כשמקור ההתעוררות מופעל, השבב מאתחל מתחילת הסקריפט הראשי – deepsleep אינו חוזר. הסקריפט מבחין בין התעוררות מ-deepsleep לבין הפעלה מחדש או reset קשה באמצעות machine.reset_cause():
import machine
if machine.reset_cause() == machine.DEEPSLEEP_RESET:
# Woke from deepsleep -- restore state from non-volatile storage,
# take a measurement, etc.
pass
else:
# Fresh boot
pass
do_work()
machine.deepsleep(60_000) # arm RTC wake for 60 s, sleep, then restart
ארגומנט המילי-שניות ל-deepsleep() דורך פנימית את אזעקת ה-RTC שעל-גבי השבב – ה-RTC הוא זה שנושא את תזמון ההתעוררות לאורך השינה, מכיוון שרוב הטיימרים האחרים מכובים. קריאה ל-deepsleep() ללא ארגומנט משאירה את ההתעוררות לכל מקור שהגדרתם בנפרד (פסיקת פין, אזעקת RTC שנדרכה חיצונית).
מכיוון שהסקריפט מופעל מחדש, כל מה שהאיטרציה הבאה צריכה חייב להיבנות מחדש בראש main.py או להישמר ל-flash (או לאוגרי הגיבוי של ה-RTC, ברכיבים שיש להם כאלה). Deepsleep נותן את החיסכון הגדול ביותר בחשמל אך מחייב את הארגון מחדש הרב ביותר של התוכנית – היישום צריך להתנהג כסדרה של ”מקבצי מדידה“ קצרים מופרדים בשינות, ולא כלולאה ארוכת-טווח עם מצב ב-RAM.
3.29.5. בחירת מצב¶
המצב הנכון תלוי במה שהמצלמה ממתינה לו:
לולאת polling צפופה, ממתינה מילי-שניות. השתמשו ב-
idle(). החיסכון קטן לכל מחזור אך גדול בסך הכל, וההתעוררות בלתי-נראית.מובטל לשניות או דקות בין אירועים. השתמשו ב-
lightsleep(). המצב נשמר, ההתעוררות מהירה, וצריכת החשמל היא חלק קטן ממצב active.מובטל לדקות או יותר בין מקבצי עבודה קצרים. השתמשו ב-
deepsleep(). השבב כבוי למעשה בין אירועים, ומבנה הסקריפט עובר ללולאת התעורר, מדוד, ישן.
יהיה המצב אשר יהיה, מקור ההתעוררות חשוב לא פחות מהמצב עצמו – deepsleep שמתעורר רק מטיימר הוא לולאת מדידה במחזור-עבודה; lightsleep שמתעורר מפסיקת פין הוא חיישן מונחה-אירועים. פונקציות השינה של מודול machine, אזעקות RTC, ו-irq() יחד נותנות את אבני הבניין.