Επέκταση C για MicroPython σε Raspberry Pi Pico

Αυτός είναι ένας οδηγός για το πώς να γράψετε και να εκτελέσετε μια βασική επέκταση C για το MicroPython στο Raspberry Pi Pico. Θα καλύψω τους λόγους για την επέκταση του MicroPython, πώς να γράψετε το module της επέκτασης, πώς να το μεταγλωττίσετε και πώς να το εγκαταστήσετε στο Pico. Αν θέλετε να διαβάσετε περισσότερα σχετικά με αυτό το θέμα, ανατρέξτε στη διεύθυνση https://docs.micropython.org/en/latest/develop/extendingmicropython.html

Εισαγωγή

Γιατί να επεκτείνετε το MicroPython;

Μπορεί να υπάρχουν πολλοί λόγοι για τους οποίους μπορεί να θέλετε να επεκτείνετε το MicroPython. Δεδομένου ότι είναι μια περικομμένη έκδοση της Python, η MicroPython δεν έχει πολύ καλές επιδόσεις όταν πρόκειται για υπολογιστικά βαριές εργασίες (παρόμοιες με την Python). Η C από την άλλη πλευρά είναι πραγματικά κατάλληλη για τέτοιες εργασίες. Μια επέκταση C για τη Micropython σας επιτρέπει να εκτελείτε αυτούς τους υπολογισμούς μέσω της γλώσσας C και να χρησιμοποιείτε τα αποτελέσματα στη MicroPython. Αυτό μπορεί να επιταχύνει ορισμένες διεργασίες κατά μια τάξη μεγέθους.

Ένας δεύτερος λόγος μπορεί να είναι ότι θέλετε να διασυνδέσετε κάποιο υλικό που χρησιμοποιεί API C μέσα από τη MicroPython. 

Τύποι επεκτάσεων MicroPython C

Υπάρχουν δύο διαφορετικοί τρόποι επέκτασης του MicroPython : εξωτερικές ενότητες C και εγγενής κώδικας μηχανής σε αρχεία .mpy.

Για να εκτελέσετε μια εξωτερική ενότητα C πρέπει να την μεταγλωττίσετε εκ νέου στο υλικολογισμικό MicroPython. Αυτή είναι μια αρκετά περίπλοκη διαδικασία, γι' αυτό και αυτός ο οδηγός θα επικεντρωθεί στη δεύτερη εναλλακτική λύση. Αν ωστόσο σας ενδιαφέρει αυτή η προσέγγιση, μπορείτε να διαβάσετε περισσότερα γι' αυτήν σε αυτές τις ιστοσελίδες:                https://docs.micropython.org/en/latest/develop/cmodules.html                      https://www.raspberrypi.org/forums/viewtopic.php?t=300352

Το .mpy είναι ένα αρχείο που αποθηκεύει μεταγλωττισμένο εγγενή κώδικα μηχανής και μπορεί να συνδεθεί δυναμικά. Αυτό το καθιστά πολύ πιο ευέλικτο, αφού δεν χρειάζεται να μεταγλωττίσετε εκ νέου ολόκληρο το firmware της MicroPython.

Γράψτε την ενότητα επέκτασης

Η συγγραφή της ενότητας επέκτασης είναι το ευκολότερο μέρος της επέκτασης του MicroPython. Θα σας δείξω πώς να το κάνετε εξετάζοντας ένα απλό παράδειγμα. Για να ξεκινήσουμε, θα δημιουργήσουμε έναν νέο κατάλογο με όνομα factfib. Ανοίξτε ένα νέο παράθυρο τερματικού, πηγαίνετε με cd στο νέο κατάλογο και δημιουργήστε ένα νέο αρχείο με όνομα factfib.c. Αν δημιουργήσατε τον κατάλογο σε ένα Raspberry Pi στο πλαίσιο του Dekstop, η εντολή μοιάζει ως εξής.

cd ~/Desktop/factfib

touch factfib.c

Ανοίξτε το factfib.c στον αγαπημένο σας επεξεργαστή κειμένου και εισάγετε τον ακόλουθο κώδικα:

#include "py/dynruntime.h

STATIC mp_int_t factorial_helper(mp_int_t x) {
   if (x < 1) {
      return 1;
   }
   return x*factorial_helper(x-1);
}

STATIC mp_obj_t factorial(mp_obj_t x_obj) {
   mp_int_t x = mp_obj_get_int(x_obj);
   mp_int_t rslt = factorial_helper(x);
   return rslt;
}

STATIC MP_DEFINE_CONST_FUN_OBJ_1(factorial_obj, factorial);

STATIC mp_int_t fibonacci_helper(mp_int_t x) {
   if (x <= 0) {
      return 0;
   }
   else if (x == 1) {
      return 1;
   }
   else {
      return (fibonacci_helper(x-1) + fibonacci_helper(x-2));
   }
}

STATIC mp_obj_t fibonacci(mp_obj_t x_obj) {
   mp_int_t x = mp_obj_get_int(x_obj);
   mp_int_t rslt = fibonacci_helper(x);
   return mp_obj_new_int(rslt);
}

STATIC MP_DEFINE_CONST_FUN_OBJ_1(fibonacci_obj, fibonacci);

mp_obj_t mpy_init(mp_obj_fun_bc_t *self, size_t n_args, size_t n_kw, mp_obj_t *args) {
   MP_DYNRUNTIME_INIT_ENTRY

   mp_store_global(MP_QSTR_factorial, MP_OBJ_FROM_PTR(&factorial_obj));
   mp_store_global(MP_QSTR_fibonacci, MP_OBJ_FROM_PTR(&fibonacci_obj));

   MP_DYNRUNTIME_INIT_EXIT
}

Επιτρέψτε μου να εξηγήσω τον παραπάνω κώδικα: Στην MicroPython και την Python, κάθε μεταβλητή είναι ένα αντικείμενο. Ως εκ τούτου, στη C τις αναπαριστούμε ως mp_obj_t. Αλλά ένα πρόγραμμα C μπορεί να δουλέψει μόνο με μεταβλητές τύπου C, γι' αυτό πρέπει να μετατρέψουμε το αντικείμενο σε τύπο C. Αυτό ονομάζεται Marshalling και το MicroPython παρέχει συναρτήσεις για την εξαγωγή οποιουδήποτε τύπου C από ένα αντικείμενο.

Αυτή η ιστοσελίδα του Oliver Robson είναι πραγματικά χρήσιμη για το Marshalling https://mpy-c-gen.oliverrobson.tech/. Επιπλέον μπορείτε να βρείτε παραδείγματα Marshalling στην τεκμηρίωση της MicroPython https://docs.micropython.org/en/latest/develop/natmod.html. Σας συμβουλεύω να διαβάσετε αυτό το άρθρο αν χρειάζεστε περισσότερες εξηγήσεις.

Κατασκευάστε την επέκταση

Δημιουργούμε την επέκταση σε ένα αρχείο .mpy χρησιμοποιώντας ένα Makefile. Αλλά πρέπει πρώτα να ρυθμίσουμε μερικά πράγματα. Βεβαιωθείτε ότι το τερματικό σας είναι ακόμα ανοιχτό στο factfib κατάλογο. Στη συνέχεια, κλωνοποιήστε το αποθετήριο MicroPython GitHub.

sudo apt-get install build-essential libreadline-dev libffi-dev git pkg-config gcc-arm-none-eabi libnewlib-arm-none-eabi

git clone --recurse-submodules https://github.com/micropython/micropython.git

pip3 install 'pyelftools>=0.25'

Αυτές οι εγκαταστάσεις θα πάρουν αρκετή ώρα, αν θέλετε να εξοικονομήσετε χρόνο και ξέρετε τι κάνετε, το μόνο που χρειάζεται είναι να κλωνοποιήσετε τον κατάλογο /py και /tools από το αποθετήριο micropython και να τα τοποθετήσετε μέσα σε ένα micropython φάκελο μέσα στο factfib (παραλείψτε τη δεύτερη εντολή).

Ενώ η εγκατάσταση εκτελείται, μπορούμε να χρησιμοποιήσουμε το χρόνο για να γράψουμε το Makefile. Απλά εκτελέστε

touch Makefile

και ανοίξτε το νεοδημιουργημένο αρχείο σε έναν επεξεργαστή κειμένου.

MPY_DIR = micropython

MOD = factfib

SRC = factfib.c

ARCH = armv7m

include $(MPY_DIR)/py/dynruntime.mk

Ίσως έχετε παρατηρήσει ότι ορίσαμε το ARCH μεταβλητή σε armv7m αν και το pico είναι armv6m. Πρέπει να το κάνουμε αυτό γιατί η armv6m αρχιτεκτονική δεν υποστηρίζεται (τη στιγμή που γράφω αυτό το άρθρο) από το dynruntime.mk εργαλείο.

Αλλά ευτυχώς μπορούμε ακόμα να συντάξουμε μια επέκταση που λειτουργεί για το Pico. Απλά πρέπει να τροποποιήσουμε το dynruntime.mk αρχείο, το οποίο θα πρέπει να βρίσκεται κάτω από micropython/py/dynruntime.mk. Ανοίξτε το και στην ενότητα Architecture configuration στο armv7m βρείτε τη μεταβλητή CFLAGS (θα πρέπει να είναι στη γραμμή 64). Αλλάξτε το -mcpu=cortex-m3 στο -mcpu=cortex-m0 και αποθηκεύστε το αρχείο.

αλλαγή -mcpu=cortex-m3 σε -mcpu=cortex-m0

Στη συνέχεια, αφού εγκατασταθούν όλα, εκτελέστε

make

και το factfib.mpy θα δημιουργηθεί το αρχείο.

Εγκατάσταση και δοκιμή της επέκτασης

Το τελευταίο βήμα είναι η εγκατάσταση και η δοκιμή. Για το σκοπό αυτό χρησιμοποιούμε το σύστημα αρχείων που δημιουργεί το Micropython στο Raspberry Pi Pico. Πρώτα πρέπει να κάνουμε flash στο Pico με το firmware της MicroPython. ο ευκολότερος τρόπος για να το κάνουμε αυτό είναι να χρησιμοποιήσουμε το Thonny IDE (προεγκατεστημένο στο Raspbian/Raspberry Pi OS).

Εάν δεν χρησιμοποιείτε ένα Raspberry Pi για να προγραμματίσετε το Pico ή εάν δεν έχετε χρησιμοποιήσει ποτέ πριν το MicroPython στο Pico, τότε ανατρέξτε στον οδηγό για τα πρώτα βήματα με το MicroPython από το Raspberry Pi. https://www.raspberrypi.org/documentation/rp2040/getting-started/#getting-started-with-micropython

Αν χρησιμοποιείτε Windows θα πρέπει να ελέγξετε αυτό το blog Post σχετικά με το Raspberry Pi Pico και MicroPython στα Windows https://picockpit.com/raspberry-pi/raspberry-pi-pico-and-micropython-on-windows/

Κλείστε το Thonny μετά την αναβάθμιση του Pico με το υλικολογισμικό MicroPython και εγκαταστήστε το rshell. Χρησιμοποιούμε το rshell για να έχουμε πρόσβαση στο σύστημα αρχείων από τη γραμμή εντολών.

sudo pip3 install rshell
rshell --version

Αυτό εκτυπώνει την έκδοση rhsell αν όλα έχουν ρυθμιστεί σωστά. Στη συνέχεια, αποσυνδέστε το pico από την πρίζα και συνδέστε το ξανά (χωρίς να κρατάτε πατημένο το κουμπί BOOTSEL) για να βεβαιωθείτε ότι τίποτα δεν προσπαθεί να αποκτήσει πρόσβαση στο σύστημα αρχείων. Τώρα πρέπει να εκτελέσουμε

rshell -p /dev/ttyACM0 --buffer-size 512

cp factfib.mpy /pyboard/factfib.mpy

Για να δοκιμάσετε την εγκατάσταση μπορείτε να χρησιμοποιήσετε είτε το rshell είτε το Thonny IDE για να αποθηκεύσετε το .py αρχεία στο Pico, αλλά θα δείξω πώς να χρησιμοποιήσετε τον διερμηνέα MicroPython μέσω του minicom.

Οπότε πρώτα πατήστε Ctrl+c για να εγκαταλείψετε το rshell και στη συνέχεια να εγκαταστήσετε το minicom μέσω

sudo apt install minicom

τώρα μπορούμε να έχουμε πρόσβαση στο Picos REPL (Read-eval-print loop)

minicom -o -D /dev/ttyACM0

Οι τρεις κλειστές αγκύλες >>> υποδεικνύουν ότι ο διερμηνέας MicroPython εκτελείται. Τώρα μπορούμε να εισάγουμε την επέκτασή μας και να δουλέψουμε μαζί της ως συνήθως.

>>> import factfib as ff

>>> ff.factorial(5)

>>> 120

>>> ff.fibonacci(7)

>>> 13

Συγχαρητήρια! Δημιουργήσατε την πρώτη σας επέκταση MicroPython C για το Pico! Το επόμενο βήμα είναι να μάθετε πώς να γράφετε και να μεταγλωττίζετε πιο σύνθετες ενότητες. Ένας καλός τρόπος για να ξεκινήσετε είναι να δοκιμάσετε πώς λειτουργεί το Marshalling των λιστών και των dicts (δείτε την ιστοσελίδα Marshalling από πάνω).

Αν έχετε οποιεσδήποτε ερωτήσεις σχετικά με αυτή τη θέση, μη διστάσετε να γράψετε ένα σχόλιο.

8 Σχόλια

  1. PeterB στις Νοέμβριος 26, 2021 στις 8:29 πμ

    Εκτός από το σφάλμα στο πρόγραμμα c λειτούργησε άψογα. Ευχαριστώ.

    STATIC mp_obj_t factorial(mp_obj_t x_obj) {
    mp_int_t x = mp_obj_get_int(x_obj),
    mp_int_t rslt = factorial_helper(x),
    return mp_obj_new_int(rslt),
    }

    • raspi berry στις Νοέμβριος 27, 2021 στις 5:56 μμ

      Σας ευχαριστούμε για τα σχόλιά σας 🙂

  2. XMC.pl στις Ιούνιος 1, 2022 στις 3:31 πμ

    Πώς να ρυθμίσετε το joomla που μπορεί να ανακτήσει τα δεδομένα από τη mysql;

  3. Lynggaard στις Ιανουάριος 8, 2023 στις 8:09 μμ

    Προσπάθησα να κάνω τα παραπάνω, αλλά διάφορα πράγματα δεν λειτουργούν όπως περιγράφεται:

    - Ακολούθησα τις παραπάνω οδηγίες, πήρα το micropython, τροποποίησα το makefile όπως περιγράφεται
    - Κάνω make (αλλά λαμβάνω ένα αρχείο factfib.native.mpy αντί για factfib.mpy)
    - Αντιγράφω το αρχείο factfib.native.mpy στο pico ως factfib.mpy
    (Δοκίμασα rshell αλλά πήρα ένα "timed out or error in transfer to remote: b"", αλλά θα μπορούσα να το αντιγράψω χρησιμοποιώντας Thonny)
    - Μπορώ να εισαγάγω την ενότητα (στο thonny ή στο rshell - το ίδιο) χωρίς σφάλματα
    - Προσπαθώ να τρέξω το "ff.fibonacci(5)", αλλά μετά λαμβάνω:

    "Traceback (πιο πρόσφατη κλήση τελευταία):
    Αρχείο "", γραμμή 1, σε
    AttributeError: Το αντικείμενο 'module' δεν έχει το χαρακτηριστικό 'fibonacci'"

    Τι κάνω λάθος;

    • paopao69 στις Μάρτιος 22, 2023 στις 5:59 μμ

      Τελικά το καταφέρατε να λειτουργήσει;

  4. Paulo στις Φεβρουάριος 9, 2024 στις 1:44 πμ

    Τώρα μπορείτε να μεταγλωττίσετε σε armv6, οπότε απλά αλλάξτε αυτή τη γραμμή στο Makefile και δεν χρειάζεται να αλλάξετε τον κώδικα micropython
    ARCH = armv6m

    Είχα μερικά σφάλματα κατά τη μεταγλώττιση του factfib.c, πού είναι οι διορθώσεις:

    // λείπει το " στο τέλος.
    #include "py/dynruntime.h"

    // μετατροπή της τιμής επιστροφής σε mp_obj_t
    STATIC mp_obj_t factorial(mp_obj_t x_obj) {
    mp_int_t x = mp_obj_get_int(x_obj),
    mp_int_t rslt = factorial_helper(x),
    return mp_obj_new_int(rslt),
    }

    • Adam στις Φεβρουάριος 9, 2024 στις 9:22 πμ

      Σε ευχαριστώ για τις πληροφορίες, Paulo!

  5. Dr_Phil στις Μάιος 24, 2024 στις 7:36 πμ

    Ακολούθησα όλες τις οδηγίες και κατέληξα σε ένα αρχείο facfib.mpy. Χρησιμοποίησα
    ARCH = armv6m
    Όταν φορτώνεται στο Pico λαμβάνω αυτό το σφάλμα:

    ValueError: ασύμβατο αρχείο .mpy

    Το Pico μου απαιτεί τις ακόλουθες τιμές mpy:
    έκδοση mpy: 6
    υπο-έκδοση mpy: 2
    σημαίες mpy: -march=armv6m

    Ο έλεγχος των δύο πρώτων bytes του αρχείου δίνει την έκδοση 6 και την υπο-έκδοση 6.
    Υπάρχει τρόπος να διορθωθεί αυτό, παρακαλώ;

Αφήστε ένα σχόλιο