{"id":37914,"date":"2019-10-31T22:20:31","date_gmt":"2019-10-31T19:20:31","guid":{"rendered":"https:\/\/prohoster.info\/blog\/opencv-na-stm32f7-discovery\/"},"modified":"2019-10-31T22:20:31","modified_gmt":"2019-10-31T19:20:31","slug":"opencv-na-stm32f7-discovery","status":"publish","type":"post","link":"https:\/\/prohoster.info\/pl\/blog\/administrirovanie\/opencv-na-stm32f7-discovery","title":{"rendered":"OpenCV na STM32F7-Discovery","gt_translate_keys":[{"key":"rendered","format":"text"}]},"content":{"rendered":"<p><img decoding=\"async\" alt=\"OpenCV na STM32F7-Discovery\" src=\"\/wp-content\/uploads\/2019\/09\/a2248ee685ee210ce8f7781435dd1d5a.jpg\" style=\"display:block;margin: 0 auto;\" \/> Jestem jednym z programist\u00f3w systemu operacyjnego <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/embox\/embox\">Embox<\/a><\/noindex>, a w tym artykule opowiem, jak uda\u0142o mi si\u0119 uruchomi\u0107 OpenCV na p\u0142ycie STM32746G.<\/p>\n<p><\/p>\n<p>Je\u015bli w wyszukiwark\u0119 wpisa\u0107 co\u015b w stylu \u201eOpenCV na p\u0142ycie STM32\u201d, mo\u017cna znale\u017a\u0107 ca\u0142kiem sporo os\u00f3b interesuj\u0105cych si\u0119 wykorzystaniem tej biblioteki na p\u0142ytach STM32 lub innych mikrokontrolerach.<br \/>\nJest kilka film\u00f3w, kt\u00f3re, s\u0105dz\u0105c po tytule, powinny demonstrowa\u0107 to, czego potrzeba, ale zazwyczaj (we wszystkich filmach, kt\u00f3re widzia\u0142em) na p\u0142ycie STM32 jedynie uzyskiwano obraz z kamery i wy\u015bwietlano wyniki na ekranie, a sama obr\u00f3bka obrazu odbywa\u0142a si\u0119 albo na zwyk\u0142ym komputerze, albo na mocniejszych p\u0142ytach (na przyk\u0142ad Raspberry Pi).<\/p>\n<p><noindex><a rel=\"nofollow\" name=\"habracut\"><\/a><\/noindex><\/p>\n<h1 id=\"pochemu-eto-slozhno\">Dlaczego to jest skomplikowane?<\/h1>\n<p><\/p>\n<p>Popularno\u015b\u0107 zapyta\u0144 w wyszukiwarkach t\u0142umaczy si\u0119 tym, \u017ce OpenCV jest najpopularniejsz\u0105 bibliotek\u0105 do komputerowego widzenia, co oznacza, \u017ce wi\u0119cej programist\u00f3w jest z ni\u0105 zaznajomionych, a mo\u017cliwo\u015b\u0107 uruchomienia kodu przygotowanego na desktopie na mikrokontrolerze znacznie upraszcza proces tworzenia. Ale dlaczego do tej pory nie ma jakich\u015b popularnych gotowych przepis\u00f3w na rozwi\u0105zanie tego problemu?<\/p>\n<p><\/p>\n<p>Problem u\u017cywania OpenCV na ma\u0142ych p\u0142ytkach wi\u0105\u017ce si\u0119 z dwiema cechami:<\/p>\n<p><\/p>\n<ul>\n<li>Nawet je\u015bli skompilujesz bibliotek\u0119 z minimalnym zestawem modu\u0142\u00f3w, w pami\u0119ci flash tej samej STM32F7Discovery po prostu si\u0119 nie zmie\u015bci (nawet bez liczenia systemu operacyjnego) z powodu bardzo du\u017cego kodu (kilka megabajt\u00f3w instrukcji)<\/li>\n<li>Sama biblioteka jest napisana w C++, co oznacza\n<ul>\n<li>Potrzebne jest wsparcie dla runtime'u C++ (wyj\u0105tki itd.)<\/li>\n<li>Brakuje wsparcia LibC\/Posix, kt\u00f3re zazwyczaj wyst\u0119puje w systemach operacyjnych dla system\u00f3w wbudowanych \u2014 potrzebna jest standardowa biblioteka C++ oraz standardowa biblioteka szablon\u00f3w STL (vector itd.)<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<p><\/p>\n<h1 id=\"portirovanie-na-embox\">Portowanie na Embox<\/h1>\n<p><\/p>\n<p>Jak zwykle przed portowaniem jakichkolwiek program\u00f3w do systemu operacyjnego, warto spr\u00f3bowa\u0107 zbudowa\u0107 go w takiej formie, w jakiej przewidzieli go programi\u015bci. W naszym przypadku nie ma z tym problemu \u2014 \u017ar\u00f3d\u0142a mo\u017cna znale\u017a\u0107 na <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/opencv\/opencv\">githubie<\/a><\/noindex>, biblioteka jest kompilowana na GNU\/Linux zwyk\u0142ym cmake'em.<\/p>\n<p><\/p>\n<p>Dla dobrych wiadomo\u015bci \u2014 OpenCV mo\u017cna budowa\u0107 jako statyczn\u0105 bibliotek\u0119, co upraszcza portowanie. Budujemy bibliotek\u0119 ze standardow\u0105 konfiguracj\u0105 i sprawdzamy, ile miejsca zajmuje. Ka\u017cdy modu\u0142 jest kompilowany do oddzielnej biblioteki.<\/p>\n<p><\/p>\n<pre><code class=\"plaintext\">&gt; size lib\/*so --totals\n   text    data     bss     dec     hex filename\n1945822   15431     960 1962213  1df0e5 lib\/libopencv_calib3d.so\n17081885     170312   25640 17277837    107a38d lib\/libopencv_core.so\n10928229     137640   20192 11086061     a928ed lib\/libopencv_dnn.so\n 842311   25680    1968  869959   d4647 lib\/libopencv_features2d.so\n 423660    8552     184  432396   6990c lib\/libopencv_flann.so\n8034733   54872    1416 8091021  7b758d lib\/libopencv_gapi.so\n  90741    3452     304   94497   17121 lib\/libopencv_highgui.so\n6338414   53152     968 6392534  618ad6 lib\/libopencv_imgcodecs.so\n21323564     155912  652056 22131532    151b34c lib\/libopencv_imgproc.so\n 724323   12176     376  736875   b3e6b lib\/libopencv_ml.so\n 429036    6864     464  436364   6a88c lib\/libopencv_objdetect.so\n6866973   50176    1064 6918213  699045 lib\/libopencv_photo.so\n 698531   13640     160  712331   ade8b lib\/libopencv_stitching.so\n 466295    6688     168  473151   7383f lib\/libopencv_video.so\n 315858    6972   11576  334406   51a46 lib\/libopencv_videoio.so\n76510375     721519  717496 77949390    4a569ce (TOTALS)<\/code><\/pre>\n<p><\/p>\n<p>Jak wida\u0107 z ostatniego wiersza, .bss i .data zajmuj\u0105 niewiele miejsca, natomiast kod zajmuje ponad 70 MiB. Oczywi\u015bcie, je\u015bli to zostanie skompilowane statycznie z konkretn\u0105 aplikacj\u0105, kod stanie si\u0119 mniejszy.<\/p>\n<p><\/p>\n<p>Spr\u00f3bujmy usun\u0105\u0107 jak najwi\u0119cej modu\u0142\u00f3w, aby stworzy\u0107 minimalny przyk\u0142ad (na przyk\u0142ad, kt\u00f3ry po prostu wy\u015bwietli wersj\u0119 OpenCV), wi\u0119c patrzymy <code>cmake .. -LA<\/code> i wy\u0142\u0105czamy we opcjach wszystko, co mo\u017cna wy\u0142\u0105czy\u0107.<\/p>\n<p><\/p>\n<pre><code class=\"plaintext\">        -DBUILD_opencv_java_bindings_generator=OFF \n        -DBUILD_opencv_stitching=OFF \n        -DWITH_PROTOBUF=OFF \n        -DWITH_PTHREADS_PF=OFF \n        -DWITH_QUIRC=OFF \n        -DWITH_TIFF=OFF \n        -DWITH_V4L=OFF \n        -DWITH_VTK=OFF \n        -DWITH_WEBP=OFF<\/code><\/pre>\n<p><\/p>\n<pre><code class=\"plaintext\">&gt; size lib\/libopencv_core.a --totals\n   text    data     bss     dec     hex filename\n3317069   36425   17987 3371481  3371d9 (TOTALS)<\/code><\/pre>\n<p><\/p>\n<p>Z jednej strony, to tylko jeden modu\u0142 biblioteki, z drugiej strony, to bez optymalizacji kompilatora pod wzgl\u0119dem rozmiaru kodu (<code>-Os<\/code>). ~3 MiB kodu \u2014 to wci\u0105\u017c do\u015b\u0107 du\u017co, ale daje ju\u017c nadziej\u0119 na sukces.<\/p>\n<p><\/p>\n<h2 id=\"zapusk-v-emulyatore\">Uruchamianie w emulatorze<\/h2>\n<p><\/p>\n<p>W emulatorze \u0142atwiej si\u0119 debugowa\u0107, wi\u0119c najpierw upewnijmy si\u0119, \u017ce biblioteka dzia\u0142a na qemu. Jako emulowana platforma wybra\u0142em Integrator\/CP, poniewa\u017c po pierwsze, to r\u00f3wnie\u017c ARM, a po drugie, Embox wspiera wyj\u015bcie graficzne dla tej platformy.<\/p>\n<p><\/p>\n<p>W Embox istnieje mechanizm do kompilacji zewn\u0119trznych bibliotek, kt\u00f3rego u\u017cywamy, aby doda\u0107 OpenCV jako modu\u0142 (przekazuj\u0105c wszystkie te same opcje dla \u201eminimalnej\u201d kompilacji w postaci statycznych bibliotek), a nast\u0119pnie dodajemy najprostsza aplikacj\u0119, kt\u00f3ra wygl\u0105da tak:<\/p>\n<p><\/p>\n<pre><code class=\"plaintext\">version.cpp:\n\n#include \n#include \n\nint main() {\n    printf(\"OpenCV: %s\", cv::getBuildInformation().c_str());\n\n    return 0;\n}<\/code><\/pre>\n<p><\/p>\n<p>Kompilujemy system, uruchamiamy \u2014 otrzymujemy oczekiwany wynik.<\/p>\n<p><\/p>\n<pre><code class=\"plaintext\">root@embox:\/&gt;opencv_version                                                     \nOpenCV: \nOg\u00f3lna konfiguracja dla OpenCV 4.0.1 =====================================\n  Kontrola wersji:               bd6927bdf-dirty\n\n  Platforma:\n    Znacznik czasu:               2019-06-21T10:02:18Z\n    Host:                        Linux 5.1.7-arch1-1-ARCH x86_64\n    Cel:                          Og\u00f3lny arm-unknown-none\n    CMake:                       3.14.5\n    Generator CMake:             Unix Makefiles\n    Narz\u0119dzie budowlane CMake:   \/usr\/bin\/make\n    Konfiguracja:                Debug\n\n  Funkcje CPU\/HW:\n    Podstawa:\n      \u017c\u0105dane:                   DETECT\n      wy\u0142\u0105czone:                VFPV3 NEON\n\n  C\/C++:\n    Zbudowany jako biblioteki dynamiczne?:   NIE<\/code><\/pre>\n<p><\/p>\n<p>Nast\u0119pnym krokiem jest uruchomienie jakiego\u015b przyk\u0142adu, najlepiej standardowego z tych, kt\u00f3re oferuj\u0105 sami tw\u00f3rcy <noindex><a rel=\"nofollow\" href=\"https:\/\/docs.opencv.org\/4.1.0\/examples.html\">na swojej stronie<\/a><\/noindex>. Wybra\u0142em <noindex><a rel=\"nofollow\" href=\"https:\/\/docs.opencv.org\/4.1.0\/d6\/d56\/samples_2cpp_2edge_8cpp-example.html\">detektor kraw\u0119dzi Canny'ego<\/a><\/noindex>.<\/p>\n<p><\/p>\n<p>Przyk\u0142ad musia\u0142em nieco przerobi\u0107, aby wy\u015bwietla\u0107 obrazek z wynikiem bezpo\u015brednio w buforze ramki. Musia\u0142em to zrobi\u0107, poniewa\u017c funkcja <code>imshow()<\/code> potrafi rysowa\u0107 obrazy przez interfejsy QT, GTK i Windows, kt\u00f3rych oczywi\u015bcie w konfiguracji dla STM32 na pewno nie b\u0119dzie. W rzeczywisto\u015bci, QT r\u00f3wnie\u017c mo\u017cna uruchomi\u0107 na STM32F7Discovery, ale o tym b\u0119dzie mowa w innym artykule \ud83d\ude42<\/p>\n<p><\/p>\n<p>Po kr\u00f3tkim ustaleniu, w jakim dok\u0142adnie formacie przechowywany jest wynik dzia\u0142ania detektora kraw\u0119dzi, otrzymujemy obraz.<\/p>\n<p>\n<img decoding=\"async\" alt=\"OpenCV na STM32F7-Discovery\" src=\"\/wp-content\/uploads\/2019\/09\/127f90ad8008340d73feb6ece02e52b2.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p>Oryginalny obrazek<\/p>\n<p>\n<img decoding=\"async\" alt=\"OpenCV na STM32F7-Discovery\" src=\"\/wp-content\/uploads\/2019\/09\/da34b3ac2561ae9f223acc5c4fe2a597.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><em>Wynik<\/em><\/p>\n<p><\/p>\n<h2 id=\"zapusk-na-stm32f7discovery\">Uruchamianie na STM32F7Discovery<\/h2>\n<p><\/p>\n<p>Na 32F746GDISCOVERY jest kilka sekcji pami\u0119ci, kt\u00f3re mo\u017cemy w ten czy inny spos\u00f3b wykorzysta\u0107<\/p>\n<p><\/p>\n<ol>\n<li>320KiB pami\u0119ci RAM<\/li>\n<li>1MiB pami\u0119ci flash dla obrazu<\/li>\n<li>8MiB SDRAM<\/li>\n<li>16MiB pami\u0119ci flash QSPI NAND<\/li>\n<li>Z\u0142\u0105cze dla karty microSD<\/li>\n<\/ol>\n<p><\/p>\n<p>Kart\u0119 SD mo\u017cna wykorzysta\u0107 do przechowywania obraz\u00f3w, ale w kontek\u015bcie uruchomienia minimalnego przyk\u0142adu nie jest to zbyt przydatne.<br \/>\nWy\u015bwietlacz ma rozdzielczo\u015b\u0107 480\u00d7272, a to oznacza, \u017ce pami\u0119\u0107 pod bufor ramki wyniesie 522 240 bajt\u00f3w przy g\u0142\u0119boko\u015bci 32 bit\u00f3w, tzn. jest to wi\u0119cej ni\u017c rozmiar pami\u0119ci operacyjnej, wi\u0119c bufor ramki oraz sterta (kt\u00f3ra b\u0119dzie potrzebna w tym wypadku dla OpenCV do przechowywania danych obraz\u00f3w i struktur pomocniczych) b\u0119d\u0105 znajdowa\u0107 si\u0119 w SDRAM, wszystko inne (pami\u0119\u0107 pod stosy i inne potrzeby systemowe) trafi do RAM.<\/p>\n<p><\/p>\n<p>Je\u015bli we\u017amiemy minimaln\u0105 konfiguracj\u0119 dla STM32F7Discovery (wyrzucimy ca\u0142\u0105 sie\u0107, wszystkie komendy, zmniejszymy stosy do minimum itp.) i dodamy do tego OpenCV z przyk\u0142adami, wymagania pami\u0119ci b\u0119d\u0105 nast\u0119puj\u0105ce:<\/p>\n<p><\/p>\n<pre><code class=\"plaintext\">   text    data     bss     dec     hex filename\n2876890  459208  312736 3648834  37ad42 build\/base\/bin\/embox<\/code><\/pre>\n<p><\/p>\n<p>Dla tych, kt\u00f3rzy nie s\u0105 zbyt zaznajomieni z tym, jakie sekcje gdzie si\u0119 umieszczaj\u0105, wyja\u015bni\u0119: w <code>.text<\/code> i <code>.rodata<\/code> znajduj\u0105 si\u0119 instrukcje i sta\u0142e (og\u00f3lnie m\u00f3wi\u0105c, dane tylko do odczytu), w <code>.data<\/code> znajduj\u0105 si\u0119 dane zmienne, w <code>.bss<\/code> le\u017c\u0105 \u201ezerowane\u201d zmienne, kt\u00f3re jednak potrzebuj\u0105 miejsca (ta sekcja \u201etrafi\u201d do RAM).<\/p>\n<p><\/p>\n<p>Dobr\u0105 wiadomo\u015bci\u0105 jest to, \u017ce <code>.data<\/code>\/<code>.bss<\/code> musz\u0105 by\u0107 umieszczone, ale z <code>.text<\/code> problemem \u2014 obraz zajmuje tylko 1MiB pami\u0119ci. Mo\u017cna usun\u0105\u0107 z <code>.text<\/code> zdj\u0119cie z przyk\u0142adu i odczyta\u0107 je, na przyk\u0142ad, z karty SD do pami\u0119ci przy starcie, ale fruits.png wa\u017cy oko\u0142o 330KiB, wi\u0119c to nie rozwi\u0105zuje problemu: du\u017c\u0105 cz\u0119\u015b\u0107 <code>.text<\/code> stanowi dok\u0142adnie kod OpenCV.<\/p>\n<p><\/p>\n<p>W gruncie rzeczy pozostaje tylko jedno - za\u0142adowanie cz\u0119\u015bci kodu na pami\u0119\u0107 QSPI-flash (ma ona specjalny tryb pracy do mapowania pami\u0119ci na magistral\u0119 systemow\u0105, dzi\u0119ki czemu procesor b\u0119dzie m\u00f3g\u0142 uzyskiwa\u0107 dost\u0119p do tych danych bezpo\u015brednio). W tym przypadku pojawia si\u0119 problem: po pierwsze, pami\u0119\u0107 QSPI-flash nie jest dost\u0119pna od razu po ponownym uruchomieniu urz\u0105dzenia (trzeba osobno zainicjowa\u0107 tryb mapowania pami\u0119ci), po drugie, nie mo\u017cna \u201ewgra\u0107\u201d tej pami\u0119ci za pomoc\u0105 zwyk\u0142ego bootloadera.<\/p>\n<p><\/p>\n<p>Ostatecznie zdecydowano si\u0119 na zlinkowanie ca\u0142ego kodu w QSPI i wgranie go w\u0142asnym bootloaderem, kt\u00f3ry pobierze potrzebny binarny plik przez TFTP.<\/p>\n<p><\/p>\n<h1 id=\"rezultat\">Wynik<\/h1>\n<p><\/p>\n<p>Pomys\u0142 przeniesienia tej biblioteki na Embox pojawi\u0142 si\u0119 ju\u017c oko\u0142o rok temu, ale nieustannie by\u0142 odk\u0142adany z r\u00f3\u017cnych powod\u00f3w. Jednym z nich by\u0142a obs\u0142uga libstdc++ i standardowej biblioteki szablon\u00f3w. Problem wsparcia C++ w Embox wykracza poza ramy tego artyku\u0142u, dlatego tutaj tylko powiem, \u017ce uda\u0142o nam si\u0119 osi\u0105gn\u0105\u0107 to wsparcie w wymaganym zakresie do dzia\u0142ania tej biblioteki \ud83d\ude42<\/p>\n<p><\/p>\n<p>Ostatecznie te problemy zosta\u0142y przezwyci\u0119\u017cone (przynajmniej w wystarczaj\u0105cym stopniu do dzia\u0142ania przyk\u0142adu OpenCV), a przyk\u0142ad uruchomi\u0142 si\u0119. 40 d\u0142ugich sekund zajmuje p\u0142ycie znalezienie kraw\u0119dzi filtrem Canny'ego. To, oczywi\u015bcie, zbyt d\u0142ugo (s\u0105 pomys\u0142y, jak to zoptymalizowa\u0107, o tym mo\u017cna by napisa\u0107 osobny artyku\u0142 w przypadku sukcesu). <\/p>\n<p>\n<img decoding=\"async\" alt=\"OpenCV na STM32F7-Discovery\" src=\"\/wp-content\/uploads\/2019\/09\/a400c72865ec17094efc985908914463.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p>Niemniej jednak, po\u015brednim celem by\u0142o stworzenie prototypu, kt\u00f3ry poka\u017ce zasadnicz\u0105 mo\u017cliwo\u015b\u0107 uruchomienia OpenCV na STM32, w zwi\u0105zku z tym cel zosta\u0142 osi\u0105gni\u0119ty, hurra!<\/p>\n<h4 id=\"tldr-poshagovaya-instrukciya\">tl;dr: krok po kroku instrukcja<\/h4>\n<p><\/p>\n<p>0: Pobieramy \u017ar\u00f3d\u0142a Embox, na przyk\u0142ad w ten spos\u00f3b:<\/p>\n<p><\/p>\n<pre><code class=\"plaintext\">    git clone https:\/\/github.com\/embox\/embox &amp;&amp; cd .\/embox<\/code><\/pre>\n<p><\/p>\n<p>1: Zaczniemy od budowy bootloadera, kt\u00f3ry \u201ewgra\u201d pami\u0119\u0107 QSPI-flash.<\/p>\n<p><\/p>\n<pre><code class=\"plaintext\">    make confload-arm\/stm32f7cube<\/code><\/pre>\n<p><\/p>\n<p>Teraz nale\u017cy skonfigurowa\u0107 sie\u0107, poniewa\u017c obraz b\u0119dziemy \u0142adowa\u0107 przez TFTP. Aby ustawi\u0107 adresy IP dla p\u0142ytki i hosta, nale\u017cy zmieni\u0107 plik conf\/rootfs\/network.<\/p>\n<p><\/p>\n<p>Przyk\u0142ad konfiguracji:<\/p>\n<p><\/p>\n<pre><code class=\"plaintext\">iface eth0 inet static\n    address 192.168.2.2\n    netmask 255.255.255.0\n    gateway 192.168.2.1\n    hwaddress aa:bb:cc:dd:ee:02<\/code><\/pre>\n<p><\/p>\n<p><code>brama<\/code> \u2014 adres hosta, z kt\u00f3rego b\u0119dzie \u0142adowany obraz, <code>address<\/code> \u2014 adres p\u0142ytki.<\/p>\n<p><\/p>\n<p>Po tym zbieramy bootloader:<\/p>\n<p><\/p>\n<pre><code class=\"plaintext\">    make<\/code><\/pre>\n<p><\/p>\n<p>2: Zwyk\u0142e wgranie bootloadera (przepraszam za kalambur) na p\u0142ytk\u0119 \u2014 tutaj nie ma nic specyficznego, nale\u017cy to zrobi\u0107 jak dla ka\u017cdej innej aplikacji dla STM32F7Discovery. Je\u015bli nie wiesz, jak to zrobi\u0107, mo\u017cna o tym poczyta\u0107 <noindex><a rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/company\/embox\/blog\/349034\/\">tutaj<\/a><\/noindex>.<br \/>\n3: Kompilacja obrazu z konfiguracj\u0105 dla OpenCV.<\/p>\n<p><\/p>\n<pre><code class=\"plaintext\">    make confload-platform\/opencv\/stm32f7discovery\n    make<\/code><\/pre>\n<p><\/p>\n<p>4: Ekstrakcja sekcji z ELF, kt\u00f3re nale\u017cy zapisa\u0107 w QSPI, do qspi.bin<\/p>\n<p><\/p>\n<pre><code class=\"plaintext\">    arm-none-eabi-objcopy -O binary build\/base\/bin\/embox build\/base\/bin\/qspi.bin \n        --only-section=.text --only-section=.rodata \n        --only-section='.ARM.ex*' \n        --only-section=.data<\/code><\/pre>\n<p><\/p>\n<p>W katalogu conf znajduje si\u0119 skrypt, kt\u00f3ry to robi, wi\u0119c mo\u017cesz go uruchomi\u0107<\/p>\n<p><\/p>\n<pre><code class=\"plaintext\">    .\/conf\/qspi_objcopy.sh # Potrzebny binarny -- build\/base\/bin\/qspi.bin<\/code><\/pre>\n<p><\/p>\n<p>5: Za pomoc\u0105 tftp \u0142adujemy qspi.bin na QSPI-flash. Na ho\u015bcie w tym celu nale\u017cy skopiowa\u0107 qspi.bin do katalogu g\u0142\u00f3wnego serwera tftp (zwykle to \/srv\/tftp\/ lub \/var\/lib\/tftpboot\/; pakiety dla odpowiedniego serwera s\u0105 w wi\u0119kszo\u015bci popularnych dystrybucji, zazwyczaj nazywa si\u0119 tftpd lub tftp-hpa, czasami trzeba uruchomi\u0107 <code>systemctl start tftpd.service<\/code> aby wystartowa\u0107).<\/p>\n<p><\/p>\n<pre><code class=\"plaintext\">    # \u0432\u0430\u0440\u0438\u0430\u043d\u0442 \u0434\u043b\u044f tftpd\n    sudo cp build\/base\/bin\/qspi.bin \/srv\/tftp\n    # \u0432\u0430\u0440\u0438\u0430\u043d\u0442 \u0434\u043b\u044f tftp-hpa\n    sudo cp build\/base\/bin\/qspi.bin \/var\/lib\/tftpboot<\/code><\/pre>\n<p><\/p>\n<p>Na Embox (tj. w bootloaderze) nale\u017cy wykona\u0107 takie polecenie (zak\u0142adaj\u0105c, \u017ce adres serwera to 192.168.2.1):<\/p>\n<p><\/p>\n<pre><code class=\"plaintext\">    embox&gt; qspi_loader qspi.bin 192.168.2.1<\/code><\/pre>\n<p><\/p>\n<p>6: Wykonujemy polecenie <code>goto<\/code> trzeba \u201eskoczy\u0107\u201d do pami\u0119ci QSPI. Konkretna lokalizacja b\u0119dzie si\u0119 r\u00f3\u017cni\u0107 w zale\u017cno\u015bci od tego, jak obraz jest linkowany, mo\u017cna j\u0105 zobaczy\u0107 za pomoc\u0105 polecenia. <code>mem 0x90000000<\/code> (adres startowy le\u017cy w drugim 32-bitowym s\u0142owie obrazu); nale\u017cy r\u00f3wnie\u017c ustawi\u0107 stos flag\u0105 <code>-s<\/code>, adres stosu znajduje si\u0119 pod adresem 0x90000000, przyk\u0142ad:<\/p>\n<p><\/p>\n<pre><code class=\"plaintext\">    embox&gt;mem 0x90000000\n    0x90000000:     0x20023200  0x9000c27f  0x9000c275  0x9000c275\n                      \u2191           \u2191\n              to jest adres    to jest adres \n                stosu        pierwszej\n                           instrukcji\n\n    embox&gt;goto -i 0x9000c27f -s 0x20023200 # Flaga -i jest potrzebna, aby zapobiec przerwom podczas inicjalizacji systemu<\/code><\/pre>\n<p><\/p>\n<p>7: Uruchamiamy<\/p>\n<p><\/p>\n<pre><code class=\"plaintext\">    embox&gt; edges 20<\/code><\/pre>\n<p><\/p>\n<p>i cieszymy si\u0119 40-sekundowym poszukiwaniem kraw\u0119dzi \ud83d\ude42<\/p>\n<p><\/p>\n<p>Je\u015bli co\u015b p\u00f3jdzie nie tak \u2014 napisz zg\u0142oszenie do <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/embox\/embox\">naszego repozytorium<\/a><\/noindex>, lub na list\u0119 embox-devel@googlegroups.com, lub w komentarzach tutaj.<\/p>\n<p>\u0179r\u00f3d\u0142o: <a content=\"nofollow\" rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/company\/embox\/blog\/457724\/\">habr.com<\/a><\/p>","protected":false,"gt_translate_keys":[{"key":"rendered","format":"html"}]},"excerpt":{"rendered":"<p>\u042f \u043e\u0434\u0438\u043d \u0438\u0437 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u043e\u0432 \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u043e\u043d\u043d\u043e\u0439 \u0441\u0438\u0441\u0442\u0435\u043c\u044b Embox, \u0438 \u0432 \u044d\u0442\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435 \u044f \u0440\u0430\u0441\u0441\u043a\u0430\u0436\u0443 \u043f\u0440\u043e \u0442\u043e, \u043a\u0430\u043a \u0443 \u043c\u0435\u043d\u044f \u043f\u043e\u043b\u0443\u0447\u0438\u043b\u043e\u0441\u044c \u0437\u0430\u043f\u0443\u0441\u0442\u0438\u0442\u044c OpenCV \u043d\u0430 \u043f\u043b\u0430\u0442\u0435 STM32746G. \u0415\u0441\u043b\u0438 \u0432\u0431\u0438\u0442\u044c \u0432 \u043f\u043e\u0438\u0441\u043a\u043e\u0432\u0438\u043a \u0447\u0442\u043e-\u0442\u043e \u0432\u0440\u043e\u0434\u0435 &#171;OpenCV on STM32 board&#187;, \u043c\u043e\u0436\u043d\u043e \u043d\u0430\u0439\u0442\u0438 \u0434\u043e\u0432\u043e\u043b\u044c\u043d\u043e \u043c\u043d\u043e\u0433\u043e \u0442\u0435\u0445, \u043a\u0442\u043e \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u0443\u0435\u0442\u0441\u044f \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435\u043c \u044d\u0442\u043e\u0439 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438 \u043d\u0430 \u043f\u043b\u0430\u0442\u0430\u0445 STM32 \u0438\u043b\u0438 \u0434\u0440\u0443\u0433\u0438\u0445 \u043c\u0438\u043a\u0440\u043e\u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440\u0430\u0445. \u0415\u0441\u0442\u044c \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0432\u0438\u0434\u0435\u043e, \u043a\u043e\u0442\u043e\u0440\u044b\u0435, \u0441\u0443\u0434\u044f [&hellip;]<\/p>\n","protected":false,"gt_translate_keys":[{"key":"rendered","format":"html"}]},"author":1,"featured_media":28450,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[688],"tags":[],"class_list":["post-37914","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-administrirovanie"],"aioseo_notices":[],"aioseo_head":"\n\t\t<!-- All in One SEO 5.0.1.1 - aioseo.com -->\n\t<meta name=\"description\" content=\"\u042f \u043e\u0434\u0438\u043d \u0438\u0437 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u043e\u0432 \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u043e\u043d\u043d\u043e\u0439 \u0441\u0438\u0441\u0442\u0435\u043c\u044b\" \/>\n\t<meta name=\"robots\" content=\"max-image-preview:large\" \/>\n\t<meta name=\"author\" content=\"Yuri Gagarin\"\/>\n\t<link rel=\"canonical\" href=\"https:\/\/prohoster.info\/pl\/blog\/administrirovanie\/opencv-na-stm32f7-discovery\" \/>\n\t<meta name=\"generator\" content=\"All in One SEO (AIOSEO) 5.0.1.1\" \/>\n\t\t<meta property=\"og:locale\" content=\"pl_PL\" \/>\n\t\t<meta property=\"og:site_name\" content=\"ProHoster | \u041a\u0443\u043f\u0438\u0442\u044c \u043d\u0430\u0434\u0435\u0436\u043d\u044b\u0439 \u0445\u043e\u0441\u0442\u0438\u043d\u0433 \u0434\u043b\u044f \u0441\u0430\u0439\u0442\u043e\u0432 \u0441 \u0437\u0430\u0449\u0438\u0442\u043e\u0439 \u043e\u0442 DDoS, VPS VDS \u0441\u0435\u0440\u0432\u0435\u0440\u044b\" \/>\n\t\t<meta property=\"og:type\" content=\"article\" \/>\n\t\t<meta property=\"og:title\" content=\"\ud83e\udd47OpenCV \u043d\u0430 STM32F7-Discovery | ProHoster\" \/>\n\t\t<meta property=\"og:description\" content=\"\u042f \u043e\u0434\u0438\u043d \u0438\u0437 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u043e\u0432 \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u043e\u043d\u043d\u043e\u0439 \u0441\u0438\u0441\u0442\u0435\u043c\u044b\" \/>\n\t\t<meta property=\"og:url\" content=\"https:\/\/prohoster.info\/pl\/blog\/administrirovanie\/opencv-na-stm32f7-discovery\" \/>\n\t\t<meta property=\"og:image\" content=\"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg\" \/>\n\t\t<meta property=\"og:image:secure_url\" content=\"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg\" \/>\n\t\t<meta property=\"og:image:width\" content=\"350\" \/>\n\t\t<meta property=\"og:image:height\" content=\"350\" \/>\n\t\t<meta property=\"article:published_time\" content=\"2019-10-31T19:20:31+00:00\" \/>\n\t\t<meta property=\"article:modified_time\" content=\"2019-10-31T19:20:31+00:00\" \/>\n\t\t<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/prohoster\" \/>\n\t\t<meta property=\"article:author\" content=\"https:\/\/www.facebook.com\/prohoster\" \/>\n\t\t<!-- All in One SEO -->\n\n","aioseo_head_json":{"title":"\ud83e\udd47OpenCV na STM32F7-Discovery | ProHoster","description":"Jestem jednym z programist\u00f3w systemu operacyjnego","canonical_url":"https:\/\/prohoster.info\/pl\/blog\/administrirovanie\/opencv-na-stm32f7-discovery","robots":"max-image-preview:large","keywords":"","webmasterTools":{"miscellaneous":""},"schema":null,"og:locale":"pl_PL","og:site_name":"ProHoster | \u041a\u0443\u043f\u0438\u0442\u044c \u043d\u0430\u0434\u0435\u0436\u043d\u044b\u0439 \u0445\u043e\u0441\u0442\u0438\u043d\u0433 \u0434\u043b\u044f \u0441\u0430\u0439\u0442\u043e\u0432 \u0441 \u0437\u0430\u0449\u0438\u0442\u043e\u0439 \u043e\u0442 DDoS, VPS VDS \u0441\u0435\u0440\u0432\u0435\u0440\u044b","og:type":"article","og:title":"\ud83e\udd47OpenCV \u043d\u0430 STM32F7-Discovery | ProHoster","og:description":"\u042f \u043e\u0434\u0438\u043d \u0438\u0437 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u043e\u0432 \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u043e\u043d\u043d\u043e\u0439 \u0441\u0438\u0441\u0442\u0435\u043c\u044b","og:url":"https:\/\/prohoster.info\/pl\/blog\/administrirovanie\/opencv-na-stm32f7-discovery","og:image":"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg","og:image:secure_url":"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg","og:image:width":350,"og:image:height":350,"article:published_time":"2019-10-31T19:20:31+00:00","article:modified_time":"2019-10-31T19:20:31+00:00","article:publisher":"https:\/\/www.facebook.com\/prohoster","article:author":"https:\/\/www.facebook.com\/prohoster"},"aioseo_meta_data":{"post_id":"37914","title":null,"description":null,"keywords":null,"keyphrases":null,"primary_term":null,"canonical_url":null,"og_title":null,"og_description":null,"og_object_type":"default","og_image_type":"default","og_image_url":null,"og_image_width":null,"og_image_height":null,"og_image_custom_url":null,"og_image_custom_fields":null,"og_video":null,"og_custom_url":null,"og_article_section":null,"og_article_tags":null,"twitter_use_og":false,"twitter_card":"default","twitter_image_type":"default","twitter_image_url":null,"twitter_image_custom_url":null,"twitter_image_custom_fields":null,"twitter_title":null,"twitter_description":null,"schema":{"blockGraphs":[],"customGraphs":[],"default":{"data":{"Article":[],"Course":[],"Dataset":[],"FAQPage":[],"Movie":[],"Person":[],"Product":[],"ProductReview":[],"Car":[],"Recipe":[],"Service":[],"SoftwareApplication":[],"WebPage":[]},"graphName":"","isEnabled":true},"graphs":[]},"schema_type":null,"schema_type_options":null,"pillar_content":false,"robots_default":true,"robots_noindex":false,"robots_noarchive":false,"robots_nosnippet":false,"robots_nofollow":false,"robots_noimageindex":false,"robots_noodp":false,"robots_notranslate":false,"robots_max_snippet":null,"robots_max_videopreview":null,"robots_max_imagepreview":"large","priority":null,"frequency":null,"local_seo":null,"seo_analyzer_scan_date":"2026-01-23 19:45:21","breadcrumb_settings":null,"limit_modified_date":false,"reviewed_by":null,"ai":null,"created":"2021-03-01 01:18:22","updated":"2026-01-23 19:45:21","focus_keyword":null,"additional_keywords":null,"truseo_locale":null},"gt_translate_keys":[{"key":"link","format":"url"}],"_links":{"self":[{"href":"https:\/\/prohoster.info\/pl\/wp-json\/wp\/v2\/posts\/37914","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/prohoster.info\/pl\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/prohoster.info\/pl\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/prohoster.info\/pl\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/prohoster.info\/pl\/wp-json\/wp\/v2\/comments?post=37914"}],"version-history":[{"count":0,"href":"https:\/\/prohoster.info\/pl\/wp-json\/wp\/v2\/posts\/37914\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/prohoster.info\/pl\/wp-json\/wp\/v2\/media\/28450"}],"wp:attachment":[{"href":"https:\/\/prohoster.info\/pl\/wp-json\/wp\/v2\/media?parent=37914"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/prohoster.info\/pl\/wp-json\/wp\/v2\/categories?post=37914"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/prohoster.info\/pl\/wp-json\/wp\/v2\/tags?post=37914"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}