Μεταφορά Qt σε STM32

Μεταφορά Qt σε STM32Καλό απόγευμα Είμαστε στο έργο Embox κυκλοφόρησε το Qt στο STM32F7-Discovery και θα ήθελα να μιλήσουμε για αυτό. Νωρίτερα, είπαμε ήδη πώς καταφέραμε να ξεκινήσουμε OpenCV.

Το Qt είναι ένα πλαίσιο πολλαπλών πλατφορμών που περιλαμβάνει όχι μόνο γραφικά στοιχεία, αλλά και πράγματα όπως το QtNetwork, ένα σύνολο κλάσεων για εργασία με βάσεις δεδομένων, το Qt για Αυτοματοποίηση (συμπεριλαμβανομένης της υλοποίησης IoT) και πολλά άλλα. Η ομάδα του Qt ήταν προληπτική σχετικά με τη χρήση του Qt σε ενσωματωμένα συστήματα, επομένως οι βιβλιοθήκες είναι αρκετά διαμορφώσιμες. Ωστόσο, μέχρι πρόσφατα, λίγοι άνθρωποι σκέφτονταν να μεταφέρουν το Qt σε μικροελεγκτές, πιθανώς επειδή μια τέτοια εργασία φαίνεται δύσκολη - το Qt είναι μεγάλο, οι MCU είναι μικρές.

Από την άλλη, αυτή τη στιγμή υπάρχουν μικροελεγκτές σχεδιασμένοι να λειτουργούν με πολυμέσα και ανώτεροι από τους πρώτους Pentium. Πριν από περίπου ένα χρόνο εμφανίστηκε το Qt blog post. Οι προγραμματιστές έφτιαξαν μια θύρα Qt για το λειτουργικό σύστημα RTEMS και κυκλοφόρησαν παραδείγματα με γραφικά στοιχεία σε πολλούς πίνακες που τρέχουν το stm32f7. Αυτό μας ενδιέφερε. Ήταν αξιοσημείωτο, και οι ίδιοι οι προγραμματιστές γράφουν γι 'αυτό, ότι το Qt είναι αργό στο STM32F7-Discovery. Αναρωτιόμασταν αν θα μπορούσαμε να εκτελέσουμε το Qt κάτω από το Embox, και όχι απλώς να σχεδιάσουμε ένα widget, αλλά να εκτελέσουμε ένα κινούμενο σχέδιο.

Το Qt 4.8 έχει μεταφερθεί στο Embox εδώ και πολύ καιρό, οπότε αποφασίσαμε να το δοκιμάσουμε. Επιλέξαμε την εφαρμογή moveblocks - ένα παράδειγμα ελαστικού κινούμενου σχεδίου.

Qt κινούμενα μπλοκ στο QEMUΜεταφορά Qt σε STM32

Αρχικά, διαμορφώνουμε το Qt, εάν είναι δυνατόν, με το ελάχιστο σύνολο στοιχείων που απαιτούνται για την υποστήριξη κινούμενων εικόνων. Για αυτό υπάρχει μια επιλογή "-qconfig minimal,small, medium...". Συνδέει ένα αρχείο διαμόρφωσης από το Qt με πολλές μακροεντολές - τι να ενεργοποιήσετε / τι να απενεργοποιήσετε. Μετά από αυτήν την επιλογή, προσθέτουμε άλλες σημαίες στη διαμόρφωση εάν θέλουμε να απενεργοποιήσουμε κάτι άλλο. Εδώ είναι ένα παράδειγμα μας διαμόρφωση.

Για να λειτουργήσει το Qt, πρέπει να προσθέσετε ένα επίπεδο συμβατότητας λειτουργικού συστήματος. Ένας τρόπος είναι η εφαρμογή QPA (Qt Platform Abstraction). Λάβαμε ως βάση το έτοιμο πρόσθετο fb_base που περιλαμβάνεται στο Qt, βάσει του οποίου λειτουργεί το QPA για Linux. Το αποτέλεσμα είναι ένα μικρό πρόσθετο που ονομάζεται emboxfb, το οποίο παρέχει στο Qt το framebuffer του Embox και στη συνέχεια σχεδιάζει εκεί χωρίς καμία εξωτερική βοήθεια.

Έτσι μοιάζει η δημιουργία ενός πρόσθετου

QEmboxFbIntegration::QEmboxFbIntegration()
    : fontDb(new QGenericUnixFontDatabase())
{
    struct fb_var_screeninfo vinfo;
    struct fb_fix_screeninfo finfo;
    const char *fbPath = "/dev/fb0";

    fbFd = open(fbPath, O_RDWR);
    if (fbPath < 0) {
        qFatal("QEmboxFbIntegration: Error open framebuffer %s", fbPath);
    }
    if (ioctl(fbFd, FBIOGET_FSCREENINFO, &finfo) == -1) {
        qFatal("QEmboxFbIntegration: Error ioctl framebuffer %s", fbPath);
    }
    if (ioctl(fbFd, FBIOGET_VSCREENINFO, &vinfo) == -1) {
        qFatal("QEmboxFbIntegration: Error ioctl framebuffer %s", fbPath);
    }
    fbWidth        = vinfo.xres;
    fbHeight       = vinfo.yres;
    fbBytesPerLine = finfo.line_length;
    fbSize         = fbBytesPerLine * fbHeight;
    fbFormat       = vinfo.fmt;
    fbData = (uint8_t *)mmap(0, fbSize, PROT_READ | PROT_WRITE,
                             MAP_SHARED, fbFd, 0);
    if (fbData == MAP_FAILED) {
        qFatal("QEmboxFbIntegration: Error mmap framebuffer %s", fbPath);
    }
    if (!fbData || !fbSize) {
        qFatal("QEmboxFbIntegration: Wrong framebuffer: base = %p,"
               "size=%d", fbData, fbSize);
    }

    mPrimaryScreen = new QEmboxFbScreen(fbData, fbWidth,
                                        fbHeight, fbBytesPerLine,
                                        emboxFbFormatToQImageFormat(fbFormat));

    mPrimaryScreen->setPhysicalSize(QSize(fbWidth, fbHeight));
    mScreens.append(mPrimaryScreen);

    this->printFbInfo();
}

Και κάπως έτσι θα είναι η επανασχεδίαση

QRegion QEmboxFbScreen::doRedraw()
{
    QVector<QRect> rects;
    QRegion touched = QFbScreen::doRedraw();

    DPRINTF("QEmboxFbScreen::doRedrawn");

    if (!compositePainter) {
        compositePainter = new QPainter(mFbScreenImage);
    }

    rects = touched.rects();
    for (int i = 0; i < rects.size(); i++) {
        compositePainter->drawImage(rects[i], *mScreenImage, rects[i]);
    }
    return touched;
}

Ως αποτέλεσμα, με ενεργοποιημένη τη βελτιστοποίηση μεταγλωττιστή για μέγεθος μνήμης -Os, η εικόνα της βιβλιοθήκης αποδείχθηκε ότι ήταν 3.5 MB, η οποία φυσικά δεν χωράει στην κύρια μνήμη του STM32F746. Όπως έχουμε ήδη γράψει σε άλλο άρθρο μας σχετικά με το OpenCV, αυτός ο πίνακας έχει:

  • 1 MB ROM
  • 320 KB RAM
  • 8 MB SDRAM
  • 16 MB QSPI

Δεδομένου ότι η υποστήριξη για την εκτέλεση κώδικα από το QSPI έχει ήδη προστεθεί στο OpenCV, αποφασίσαμε να ξεκινήσουμε φορτώνοντας ολόκληρη την εικόνα Embox c Qt στο QSPI. Και ρε, όλα ξεκίνησαν σχεδόν αμέσως από το QSPI! Αλλά όπως και στην περίπτωση του OpenCV, αποδείχθηκε ότι λειτουργεί πολύ αργά.

Μεταφορά Qt σε STM32

Επομένως, αποφασίσαμε να το κάνουμε με αυτόν τον τρόπο - πρώτα αντιγράφουμε την εικόνα στο QSPI, στη συνέχεια τη φορτώνουμε στο SDRAM και την εκτελούμε από εκεί. Από το SDRAM έγινε λίγο πιο γρήγορο, αλλά ακόμα μακριά από το QEMU.

Μεταφορά Qt σε STM32

Στη συνέχεια, υπήρχε μια ιδέα να συμπεριληφθεί μια κινητή υποδιαστολή - τελικά, το Qt κάνει μερικούς υπολογισμούς των συντεταγμένων των τετραγώνων στο κινούμενο σχέδιο. Προσπαθήσαμε, αλλά εδώ δεν είχαμε ορατή επιτάχυνση, αν και μέσα άρθρο Οι προγραμματιστές του Qt ισχυρίστηκαν ότι το FPU δίνει σημαντική αύξηση στην ταχύτητα για «σύροντας κινούμενα σχέδια» στην οθόνη αφής. Μπορεί να υπάρχουν σημαντικά λιγότεροι υπολογισμοί κινητής υποδιαστολής σε κινούμενα μπλοκ, και αυτό εξαρτάται από το συγκεκριμένο παράδειγμα.

Η πιο αποτελεσματική ιδέα ήταν να μετακινήσετε το framebuffer από το SDRAM στην εσωτερική μνήμη. Για να γίνει αυτό, φτιάξαμε τις διαστάσεις της οθόνης όχι 480x272, αλλά 272x272. Μειώσαμε επίσης το βάθος χρώματος από A8R8G8B8 σε R5G6B5, μειώνοντας έτσι το μέγεθος ενός pixel από 4 σε 2 byte. Το μέγεθος του framebuffer που προκύπτει είναι 272 * 272 * 2 = 147968 byte. Αυτό έδωσε μια σημαντική επιτάχυνση, ίσως το πιο αισθητό, το κινούμενο σχέδιο έγινε σχεδόν ομαλό.

Η πιο πρόσφατη βελτιστοποίηση ήταν η εκτέλεση κώδικα Embox από τη μνήμη RAM και κώδικας Qt από SDRAM. Για να γίνει αυτό, πρώτα, ως συνήθως, συνδέουμε στατικά το Embox μαζί με το Qt, αλλά τοποθετούμε τα τμήματα κειμένου, rodata, δεδομένων και bss της βιβλιοθήκης στο QSPI για να το αντιγράψουμε στη συνέχεια στο SDRAM.

section (qt_text, SDRAM, QSPI)
phdr	(qt_text, PT_LOAD, FLAGS(5))

section (qt_rodata, SDRAM, QSPI)
phdr	(qt_rodata, PT_LOAD, FLAGS(5))

section (qt_data, SDRAM, QSPI)
phdr	(qt_data, PT_LOAD, FLAGS(6))

section (qt_bss, SDRAM, QSPI)
phdr	(qt_bss, PT_LOAD, FLAGS(6))

Εκτελώντας τον κωδικό Embox από τη ROM, λάβαμε επίσης μια αξιοσημείωτη επιτάχυνση. Ως αποτέλεσμα, το animation έγινε αρκετά ομαλό:


Στο τέλος, κατά την προετοιμασία του άρθρου και τη δοκιμή διαφορετικών διαμορφώσεων Embox, αποδείχθηκε ότι τα Qt moveblocks λειτουργούν εξαιρετικά από το QSPI με ένα framebuffer στο SDRAM και το σημείο συμφόρησης ήταν ακριβώς το μέγεθος του framebuffer! Προφανώς, για να ξεπεραστεί το αρχικό "slideshow", μια διπλή επιτάχυνση ήταν αρκετή λόγω μιας απλής μείωσης του μεγέθους του framebuffer. Αλλά δεν ήταν δυνατό να επιτευχθεί ένα τέτοιο αποτέλεσμα μεταφέροντας μόνο τον κωδικό Embox σε διάφορες γρήγορες μνήμες (η επιτάχυνση δεν ήταν 2, αλλά περίπου 2 φορές).

Πώς να το δοκιμάσετε μόνοι σας

Εάν έχετε ένα STM32F7-Discovery, μπορείτε να εκτελέσετε μόνοι σας το Qt στο Embox. Μπορείτε να διαβάσετε πώς γίνεται αυτό στο δικό μας wiki.

Συμπέρασμα

Ως αποτέλεσμα, καταφέραμε να λανσάρουμε το Qt! Η πολυπλοκότητα του έργου, κατά τη γνώμη μας, είναι κάπως υπερβολική. Φυσικά, πρέπει να λάβετε υπόψη τις ιδιαιτερότητες των μικροελεγκτών και γενικά να κατανοήσετε την αρχιτεκτονική των συστημάτων υπολογιστών. Τα αποτελέσματα βελτιστοποίησης δείχνουν το γνωστό γεγονός ότι το σημείο συμφόρησης σε ένα υπολογιστικό σύστημα δεν είναι ο επεξεργαστής, αλλά η μνήμη.

Φέτος θα συμμετάσχουμε στο φεστιβάλ TechTrain. Εκεί θα σας πούμε με περισσότερες λεπτομέρειες και θα δείξουμε το Qt, το OpenCV σε μικροελεγκτές και τα άλλα μας επιτεύγματα.

Πηγή: www.habr.com

Προσθέστε ένα σχόλιο