ลำดับการรีเซ็ตและการบูต¶
อุปกรณ์ที่รัน MicroPython จะทำตามลำดับการบูตเฉพาะเพื่อเริ่มต้นและเริ่มการทำงานหลังจากรีเซ็ต
Note
ลำดับ _boot.py → boot.py → main.py → REPL ที่อธิบายด้านล่างคือสิ่งที่เฟิร์มแวร์รันในทุกการรีเซ็ต โดยไม่คำนึงถึงวิธีที่คุณเชื่อมต่อ ดังนั้นจึงใช้ได้เสมอ เมื่อคุณรันสคริปต์จาก OpenMV IDE IDE จะหยุด main.py ที่กำลังรันอยู่และรันสคริปต์ที่เปิดอยู่ในโปรแกรมแก้ไขแทน ผ่านโปรโตคอลดีบักของตัวเอง โดยไม่ใช้ REPL บนอุปกรณ์ ดังนั้นการอ้างอิง เฉพาะ REPL ในหน้านี้ (พรอมต์แบบโต้ตอบ Ctrl-D / Ctrl-C ที่เทอร์มินัลแบบอนุกรม ฯลฯ) ใช้กับการทำงานแบบอิสระและการใช้งานผ่านเทอร์มินัลแบบอนุกรมโดยตรง แต่ลำดับการบูตเองใช้ได้กับทุกกรณี
รีเซ็ตแบบฮาร์ด¶
การบูตจากการรีเซ็ตแบบฮาร์ดเกิดขึ้นเมื่อบอร์ดได้รับการจ่ายไฟครั้งแรก ซึ่งเป็นการบูตเย็น ถือเป็นการรีเซ็ตฮาร์ดแวร์ MCU อย่างสมบูรณ์
โค้ด port ของ MicroPython จะเริ่มต้นฮาร์ดแวร์ที่จำเป็นทั้งหมด (รวมถึงนาฬิกาและตัวควบคุมพลังงานที่ฝังอยู่ UART ภายใน เป็นต้น) จากนั้นเริ่ม MicroPython environment การกำหนดค่า RTC ที่มีอยู่อาจถูกรักษาไว้หลังการรีเซ็ตแบบฮาร์ด แต่สถานะฮาร์ดแวร์อื่น ๆ ทั้งหมดจะถูกล้าง
ลำดับการบูตหลังรีเซ็ตแบบฮาร์ดเดียวกันสามารถเกิดขึ้นได้จากหลายเหตุการณ์ เช่น:
โค้ด Python ที่รัน
machine.reset()ผู้ใช้กดปุ่มรีเซ็ตทางกายภาพบนบอร์ด (ถ้ามี)
การตื่นจากโหมดสลีปลึก (ในพอร์ตส่วนใหญ่)
การรีเซ็ตจาก watchdog ของฮาร์ดแวร์ MCU
ตัวตรวจจับ brown out ของฮาร์ดแวร์ MCU
รายละเอียดของตัวกระตุ้นการรีเซ็ตเฉพาะฮาร์ดแวร์ขึ้นอยู่กับ port และฮาร์ดแวร์ที่เกี่ยวข้อง ฟังก์ชัน machine.reset_cause() สามารถใช้เพื่อระบุสาเหตุของการรีเซ็ตเพิ่มเติมได้
รีเซ็ตแบบซอฟต์¶
เมื่อ MicroPython กำลังรันอยู่แล้ว คุณสามารถกระตุ้นการรีเซ็ตแบบซอฟต์โดย พิมพ์ Ctrl-D ใน REPL หรือรัน machine.soft_reset()
การรีเซ็ตแบบซอฟต์จะล้างตัวแปลภาษา Python คืนหน่วยความจำ Python ทั้งหมด และเริ่ม MicroPython environment อีกครั้ง
สถานะที่ถูกล้างโดยการรีเซ็ตแบบซอฟต์ประกอบด้วย:
ตัวแปร Python ออบเจ็กต์ โมดูลที่นำเข้า และอื่น ๆ ทั้งหมด
อุปกรณ์ต่อพ่วงส่วนใหญ่ที่กำหนดค่าโดยใช้ machine module มีข้อยกเว้นจำกัดมาก เช่น โหมด machine.Pin (คือ หากพินเป็น input หรือ output สูงหรือต่ำ) จะไม่ถูกรีเซ็ตในพอร์ตส่วนใหญ่ การกำหนดค่าขั้นสูง เช่น
Pin.irq()จะถูกรีเซ็ตเสมอBluetooth
ซ็อกเก็ตเครือข่าย TCP ที่เปิดอยู่จะถูกปิดอย่างสะอาดโดยคำนึงถึงอีกฝ่าย
ไฟล์ที่เปิดอยู่ ระบบไฟล์จะถูกทิ้งไว้ในสถานะที่ถูกต้อง
สถานะของระบบบางอย่างยังคงเหมือนเดิมหลังการรีเซ็ตแบบซอฟต์ รวมถึง:
การเชื่อมต่อเครือข่ายที่มีอยู่ (Ethernet, Wi-Fi และอื่น ๆ) ยังคงทำงานอยู่ในชั้น IP Network การสอบถาม network interface จากโค้ด อาจแสดงว่า network interface ยังคงทำงานอยู่พร้อม IP address ที่กำหนดค่าแล้ว เป็นต้น
REPL ที่ทำงานอยู่จะปรากฏต่อเนื่องก่อนและหลังการรีเซ็ตแบบซอฟต์ ยกเว้นในบางกรณีที่ผิดปกติ:
REPL ของ UART แบบอนุกรมจะคืนค่าการกำหนดค่าฮาร์ดแวร์เริ่มต้น (อัตราบอด เป็นต้น)
ความเร็วสัญญาณนาฬิกา CPU โดยปกติจะไม่เปลี่ยนแปลงจากการรีเซ็ตแบบซอฟต์
การกำหนดค่า RTC (คือ การตั้งเวลาปัจจุบัน) จะไม่ถูกเปลี่ยนแปลงโดยการรีเซ็ตแบบซอฟต์
ลำดับการบูต¶
เมื่อ MicroPython บูตหลังจากรีเซ็ตแบบฮาร์ดหรือซอฟต์ จะทำตามลำดับการบูตนี้ตามลำดับ:
_boot.py¶
นี่คือสคริปต์ภายใน ที่ถูก frozen ลงในเฟิร์มแวร์ MicroPython โดย MicroPython มอบให้สำหรับหลาย port เพื่อทำการเริ่มต้นที่จำเป็น
ตัวอย่างเช่น ในพอร์ตส่วนใหญ่ _boot.py จะตรวจจับการบูตครั้งแรกของอุปกรณ์ใหม่และฟอร์แมต ระบบไฟล์แฟลชภายใน ให้พร้อมใช้งาน
เว้นแต่คุณกำลังสร้าง MicroPython build แบบกำหนดเองหรือเพิ่ม port ใหม่ คุณอาจไม่ต้องกังวลเกี่ยวกับ _boot.py ควรหลีกเลี่ยงการเปลี่ยนเนื้อหาเว้นแต่คุณจะรู้ว่าคุณกำลังทำอะไรอยู่จริง ๆ
boot.py¶
ไฟล์ชื่อ boot.py สามารถคัดลอกไปยัง filesystem ภายในของบอร์ดโดยใช้ mpremote
หากพบ boot.py ก็จะถูกรัน คุณสามารถเพิ่มโค้ดใน boot.py เพื่อทำการเริ่มต้นครั้งเดียวแบบกำหนดเอง (เช่น เพื่อกำหนดค่าฮาร์ดแวร์ของบอร์ด)
แนวทางปฏิบัติทั่วไปคือการกำหนดค่าการเชื่อมต่อเครือข่ายของบอร์ดใน boot.py เพื่อให้พร้อมใช้งานเสมอหลังรีเซ็ตสำหรับ REPL, mpremote เป็นต้น
Warning
boot.py ควรออกเสมอและไม่รันแบบไม่มีที่สิ้นสุด
ขึ้นอยู่กับบอร์ด การเริ่มต้นฮาร์ดแวร์บางอย่างจะถูกเลื่อนออกไปจนกว่า boot.py จะออก ซึ่งรวมถึงการเริ่มต้น USB บน OpenMV Cams ที่ใช้ STM32 บนบอร์ดเหล่านี้ ข้อความที่พิมพ์จาก boot.py อาจไม่ปรากฏบนพอร์ต USB serial ในตัวจนกว่า boot.py จะรันเสร็จ
วัตถุประสงค์ของการเริ่มต้นล่าช้านี้คือเพื่อให้สามารถกำหนดค่าฮาร์ดแวร์เฉพาะล่วงหน้าใน boot.py แล้วให้มันเริ่มด้วยการกำหนดค่าที่ถูกต้อง
Note
บางครั้งการไม่มีไฟล์ boot.py และวางโค้ดการเริ่มต้นไว้ที่ด้านบนของ main.py แทนจะง่ายกว่า
main.py¶
คล้ายกับ boot.py ไฟล์ชื่อ main.py สามารถคัดลอกไปยัง filesystem ภายในของบอร์ดได้ หากพบก็จะถูกรันต่อไปในกระบวนการเริ่มต้น
main.py ใช้สำหรับโค้ด Python ที่คุณต้องการรันทุกครั้งที่อุปกรณ์เริ่มต้น
เคล็ดลับบางประการสำหรับการใช้ main.py:
main.pyไม่จำเป็นต้องออก คุณสามารถใส่ลูปwhile Trueแบบอนันต์ได้อย่างอิสระสำหรับแอปพลิเคชัน Python ที่ซับซ้อน คุณไม่จำเป็นต้องใส่โค้ดทั้งหมดใน
main.pymain.pyสามารถเป็นจุดเข้าใช้งานแบบง่ายที่นำเข้าแอปพลิเคชันของคุณและเริ่มการรัน:import my_app my_app.main()
วิธีนี้ช่วยให้โครงสร้างของแอปพลิเคชันชัดเจน และยังทำให้ง่ายต่อการติดตั้งหลายแอปพลิเคชันบนบอร์ดและสลับระหว่างกัน
แนวทางปฏิบัติที่ดีเมื่อเขียนแอปที่แข็งแกร่งคือการล้อมโค้ดใน
main.pyด้วยตัวจัดการข้อยกเว้นเพื่อดำเนินการที่เหมาะสมหากโค้ดเกิดข้อผิดพลาด ตัวอย่างเช่น:import machine, sys import my_app try: my_app.main() except Exception as e: print("Fatal error in main:") sys.print_exception(e) # Following a normal Exception or main() exiting, reset the board. # Following a non-Exception error such as KeyboardInterrupt (Ctrl-C), # this code will drop to a REPL. Place machine.reset() in a finally # block to always reset, instead. machine.reset()
มิฉะนั้น MicroPython จะออกไปยัง REPL หลังจากเกิดข้อผิดพลาดหรือถ้า main ออก (ดูด้านล่าง)
ตัวแปร global ที่ถูกตั้งค่าใน
boot.pyจะยังคงถูกตั้งค่าในบริบท global ของmain.pyเพื่อเพิ่มประสิทธิภาพการใช้แฟลชและการใช้หน่วยความจำ คุณสามารถคัดลอกไฟล์ ที่คอมไพล์ล่วงหน้า
main.mpyและ/หรือboot.mpyไปยัง filesystem หรือแม้แต่ freeze ลงในบิลด์เฟิร์มแวร์แทนการรัน
main.pyจะถูกข้ามเมื่อการรีเซ็ตแบบซอฟต์เริ่มต้นจาก โหมด raw REPL (เช่น เมื่อ mpremote หรือโปรแกรมอื่นกำลังโต้ตอบโดยตรงกับ MicroPython)
ตัวแปลคำสั่งแบบโต้ตอบ (REPL)¶
หากไม่พบ main.py หรือถ้า main.py ออก โหมดอินเทอร์พรีเตอร์แบบโต้ตอบของ MicroPython (หรือที่รู้จักกันในชื่อ REPL) จะเริ่มต้นทันที
Note
แม้ว่า main.py จะมีลูปแบบอนันต์ การพิมพ์ Ctrl-C บนพอร์ต REPL แบบอนุกรมจะส่ง KeyboardInterrupt หากไม่มีตัวจัดการข้อยกเว้นใดรับมัน main.py จะออกและ REPL จะเริ่มต้น
ตัวแปร global ที่ถูกตั้งค่าใน boot.py และ main.py จะยังคงถูกตั้งค่าในบริบท global ของ REPL
REPL ยังคงรันต่อเนื่องจนกว่าโค้ด Python จะกระตุ้นการรีเซ็ตแบบฮาร์ดหรือซอฟต์
Soft Bricking (การบูตล้มเหลว)¶
แม้จะเป็นเรื่องหายาก แต่ก็เป็นไปได้ที่ MicroPython จะไม่ตอบสนองระหว่างการเริ่มต้น สถานะที่บางครั้งเรียกว่า "soft bricked" ตัวอย่างเช่น:
หากการรัน
boot.pyติดค้างและพอร์ต USB serial ดั้งเดิมไม่เริ่มต้นหากโค้ด Python กำหนดค่าอินเทอร์เฟซ REPL ใหม่ ทำให้เข้าถึงไม่ได้
อย่ากังวล การกู้คืนเป็นไปได้!
หากคุณใช้ OpenMV IDE การเชื่อมต่อเพียงอย่างเดียวมักเพียงพอ — IDE จะหยุด main.py ที่กำลังรันและเข้าควบคุม หากกล้องไม่สามารถเชื่อมต่อได้เลย ให้ใช้ Factory Reset ด้านล่าง วิธี Ctrl-C ที่อธิบายต่อไปนี้ใช้สำหรับการใช้งานเทอร์มินัลแบบอนุกรมโดยตรง — อาศัย REPL บนอุปกรณ์ ซึ่ง OpenMV IDE ไม่ใช้
KeyboardInterrupt¶
ในหลายกรณี การเปิดพอร์ต REPL แบบอนุกรมและพิมพ์ Ctrl-C จะส่ง KeyboardInterrupt และอาจทำให้สคริปต์ที่รันอยู่ออกและ REPL เริ่มต้น จาก REPL คุณสามารถใช้ os.remove() เพื่อลบไฟล์ Python ที่มีปัญหา:
import os
os.remove('main.py')
เพื่อยืนยันว่าไฟล์ใดยังคงอยู่ใน filesystem ภายใน:
import os
os.listdir()
Factory Reset¶
หากคุณไม่สามารถเข้าถึง REPL โดยใช้วิธีข้างต้น ตัวเลือกที่เหลือคือการ factory reset: การลบเนื้อหาทั้งหมดของ filesystem แฟลชภายใน วิธีนี้ยังเป็นการแก้ไขหาก filesystem ภายในเสียหาย
OpenMV IDE มีหลายวิธีในตัวเพื่อทำสิ่งนี้ ขั้นแรกนำกล้องเข้าสู่โหมด recovery/bootloader — วิธีการต่างกันตามบอร์ด ดังนั้นดูส่วน Recovery and debug pins ในเอกสาร quick reference ของบอร์ดคุณเพื่อดูวิธีเข้า จากนั้นคลิกปุ่มเชื่อมต่อใน OpenMV IDE และทำตามคำแนะนำเพื่อลบ filesystem และแฟลชเฟิร์มแวร์ใหม่
Warning
การแฟลชเฟิร์มแวร์ใหม่ โดยไม่ ลบ filesystem มักจะไม่สามารถกู้คืนจาก soft bricking ได้ เนื่องจากการอัปเดตเฟิร์มแวร์ปกติจะรักษาเนื้อหาของ filesystem ไว้ ตรวจสอบให้แน่ใจว่าเลือกตัวเลือกลบเมื่อ OpenMV IDE ถามถึงมัน
หากคุณติดปัญหา ถามได้ที่ OpenMV forums