Elektroda.pl
Elektroda.pl
X
Please add exception to AdBlock for elektroda.pl.
If you watch the ads, you support portal and users.

Podstawowe użycie toolchain'a arm-none-eabi czyli co się dzieje przed main

_lazor_ 18 Nov 2018 17:26 9213 31
NDN
  • Wstęp

    Poradniki pomagające w tworzeniu oprogramowania na mikrokontrolery skupiają się głównie na wykorzystaniu peryferiów samego mikrokontrolera, co jest zrozumiałe, ale niestety rzadko skncentrują się na części programu, która wykonuje się przed funkcją main.
    Poniższy poradnik ma na celu przybliżenie tej części programu na podstawie GNU ARM toolchain oraz mikrokontrolera stm32F334 z rdzeniem cortex-m4.


    Używane narzędzia:
    - GNU Arm Embedded Toolchain 7-2018-q2-update
    https://developer.arm.com/open-source/gnu-toolchain/gnu-rm/downloads

    - OpenOCD
    - cygwin (z make)
    - puTTy
    - sterowniki wymagane przez STLINK

    Zainstalować powyższe programy i dodać do zmiennej środowiskowej Path ścieżkę do folderu bin dla toolchain’a (dla naszej wygody, inaczej za każdym razem trzeba podawać relatywną ścieżkę do narzędzi).

    1. Startup

    Od czego zacząć pisanie kodu? Od poszukiwania informacji na temat jak producent rdzenia (w tym wypadku ARM) przewidział startup procesora:

    https://www.keil.com/pack/doc/CMSIS/Core/html/startup_s_pg.html

    Nasz kod zaczyna się od adresu 0x00000000 gdzie znajduje się wartość stack pointera, a następnie program zaczyna się pod adresem 0x00000004 gdzie znajduje się początek vector table, której pierwszym elementem jest pointer na funkcję „Reset_Handler”.
    Jest możliwość zmiany adresu pamięci z jakiego nasz program się uruchamia. Jest to możliwe za pomocą fizycznej ingerencji w piny oznaczone jako BOOT0 i nBOOT1. Co ciekawe, możemy wystartować program z „System memory „ gdzie znajduje się „Embedded boot loader „ który jest wgrywany podczas produkcji układu i nie jest możliwy do modyfikacji.
    Więcej informacji o Embedded boot loader’a można znaleźć pod linkiem:
    https://www.st.com/content/ccc/resource/technical/document/application_note/b9/9b/16/3a/12/1e/40/0c/CD00167594.pdf/files/CD00167594.pdf/jcr:content/translations/en.CD00167594.pdf

    Możemy teraz przystąpić do pisania własnego kodu startup.S. Czym jest ten plik? Jest to plik napisany w języku asembly zwanym u nas assembleerem. Język assembly składa się z dwóch zestawów instrukcji: ARM i thumb (thumb-2). Więcej na ten temat można poczytać w tym wątku:
    https://stackoverflow.com/questions/28669905/what-is-the-difference-between-the-arm-thumb-and-thumb-2-instruction-encodings
    W naszym przypadku używamy zestawu instrukcji thumb-2:
    http://infocenter.arm.com/help/topic/com.arm.doc.qrc0001m/QRC0001_UAL.pdf

    Code: text
    Log in, to see the code


    1. dyrektywa .global powoduje że symbol _start jest widoczna dla linkera (ld)
    2.dyrektywa .thumb_func mówi assemblerowi (as) że następny symbol wskazuje na instrukcje thumb
    3. adres stack point’a, którego wartość znajdzie się pod adresem 0x08000000 flash. Aktualnie zostanie ustawiony na koniec pamięci SRAM, który możemy odczytać z dokumentacji mikrokontrolera.
    4. vector reset, który znajdzie się pod adresem 0x08000004 flash. Zawartość tego adresu zawiera adres na funkcję reset:
    5. Branch – przeskoczenie do funkcji o etykiecie (adresie) bez wpisywania adresu do lr (link register).
    6. Kod nigdy nie powinien się tutaj znaleźć.
    7. Funkcja z nieskończoną pętlą.

    2. Skrypt Linkera

    Jeśli mamy już nasz startup to możemy zacząć pisać nasz skrypt linkera. Poniższy skrypt opisuje jaki kod (i w jakiej kolejności) będzie trafiał do poszczególnych sekcji oraz dostarczy nam informacje o początkach i końcach poszczególnych sekcji.

    Code: text
    Log in, to see the code


    1. MEMORY przydziela nazwy do przestrzeni pamięci.
    2. Początek pamięci flash oraz długość. Informacja o adresie w dokumentacji
    3. Początek pamięci oraz długość Ram. Ponownie informacja o adresie w dokumentacji
    4. sekcja .text w tej sekcji znajduje się kod wykonywalny.
    5. adres początku sekcji. Możemy również ustawić adres sekcji ręcznie poprzez . = 0x80000;
    6. Wrzucenie wszystkich text z obiektów do tej sekcji
    7 i 8. Wrzucenie konkretnych text z obiektów do tej przestrzeni. Trzeba mieć na uwadze, że zamiana kolejności obiektów spowoduje, że kod nie będzie działać poprawnie!
    9. Adres końca sekcji
    10. Wskazanie na jaki adres będzie leciała dana sekcja.
    11. Sekcja .rodata zawiera wszystkie zmienne stałe.
    12.Sekcja .bss (block started by symbol) zawiera wszystkie zmienne statyczne nie zainicjalizowane.
    13. Sekcja .data zawiera wszystkie zmienne statyczne zainicjalizowane. Zapis „AT (__rodata_end__)” Oznacza tyle, że sekcja chociaż znajdować się będzie w SRAM to na początku fizycznie będzie znajdować się w flash i trzeba ją następnie przekopiować w cstartup do ramu.

    3. cstartup

    Jeśli mamy już nasz skrypt linkera to możemy zacząć pisać nasz własny crt0. Jest to kawałek kodu wykonywany przed funkcją main, która zapewnia skopiowanie wszelakich statycznych danych z pamięci nieulotnej do ulotnej (w przypadku statycznych niezainicjalizowane zmiennych, wyzerowanie ich).
    Tak więc tak wygląda nasz _cstartup:
    Code: text
    Log in, to see the code


    Jest to kod napisany w C, jednak bez żadnych przeszkód możemy go napisać w asm.
    Zmienne globalne zaczynające się od extern są zmiennymi zawierające informację o adresach początku i końca sekcji, które będą szczegółowiej opisane w części poświęconej linkerowi. Powyższy kod zeruje przestrzeń .bss gdzie znajdują się niezainicjalizowane zmienne statyczne, gdy do sekcji .data zostają przeniesione z pamięci nieulotnej wszystkie zainicjalizowane zmienne statyczne.
    Ważne wspomnieć, że jeśli chcemy by inne sekcje również znajdowały się w RAM (np. sekcja z kodem, który ma się wykonywać z RAM’u), również tutaj muszą zostać przekopiowane.


    4. Main

    Gdy już mamy napisane wszystkie elementy związane z startup'em możemy przystąpić do pisania naszej funkcji main:
    Code: c
    Log in, to see the code


    Adres RCCBASE oraz GPIOBASE możemy odczytać z dokumentacji z opisem za co poszczególne rejestry odpowiadają. Komentarze w kodzie są wystarczając i ten kawałek kodu nie wymaga dłuższego omówienia. Możemy teraz przejść do omówienia sposobu budowania projektu.

    5. Makefile

    Code: makefile
    Log in, to see the code


    To co powyżej widzimy to plik makefile, który zawiera opis budowania naszego projektu. Sposób budowania jest specjalnie uproszczony by w dość przejrzysty sposób wytłumaczyć na czym polega proces budowania binarki.

    Zaczynamy od kompilatora gcc. Jest to program kombajn, który wiele może zrobić za naszymi plecami, ale jego głównym założeniem jest kompilacja plików napisanych w C do plików w języku asm. W tym wypadku zachodzi niejawne użycie programu as (assembler), który tłumaczy assembly na język maszynowy.
    Opis poszczególnych flag użytych podczas wywołania kompilatora i as (niejawnie):
    -Wall Wyświetla wszystkie warningi, które zostały wykryte w kodzie.
    -g zamieszcza w outpucie symbole debugowe.
    -c kompilowanie i asemblowanie plików źródłowych bez ich linkowania.
    -o file nazwa pliku wyjściowego
    -march Nazwa architektury pod którą budujemy projektu

    Gdy już uzyskamy pliki .o możemy przystąpić do linkowania za pomocą ld z flagą -T która powoduje, że linker używa naszego skryptu.
    Kolejnymi dwoma narzędziami są objdump oraz nm, które mogą nam pomóc w lepszym zrozumieniu naszego kodu oraz są wielce pomocne podczas poszukiwania pewnych rodzajów błędów w kodzie.
    Na samym końcu używamy objcopy do translacji pliku .elf na plik binarny.


    Opis wszystkich opcji gcc:
    https://gcc.gnu.org/onlinedocs/gcc/Option-Summary.html


    Gdy posiadamy już nasz plik binarny oraz używamy ST Link’a, który zgłasza się jako mass storage device po podpięciu pod USB, możemy przerzucić bezpośrednio wygenerowaną binarkę do ST Link’a a flashowanie zacznie się automatycznie. Nasz układ zaczyna mrugać LED!

    Efekt końcowy:





    6. Debugowanie
    Ważne! Kompilator musi budować z flagą -g !

    flashujemu nasz układ poprzez openocd:
    $ openocd -f ../OpenOCD/0.10.0-9-20181016-1725/scripts/board/stm32f334discovery.cfg -c init -c "reset halt" -c "flash write_image erase blink.elf" -c "verify_image blink.elf" -c reset -c shutdown

    Podstawowe użycie toolchain'a arm-none-eabi czyli co się dzieje przed main

    następnie odpalamy openocd z plikiem konfiguracyjnym dla naszego boarda:
    openocd -f ../OpenOCD/0.10.0-9-20181016-1725/scripts/board/st_nucleo_f3.cfg

    Podstawowe użycie toolchain'a arm-none-eabi czyli co się dzieje przed main

    następnie odpalamy puTTy i łaczymy pod adres 127.0.0.1 na porcie 4444 poprzez telnet
    jeśli coś nie działa musimy odblokować clienta telnet:
    https://www.lifewire.com/what-is-telnet-2626026

    Podstawowe użycie toolchain'a arm-none-eabi czyli co się dzieje przed main

    Gdy już odpaliliśmy puTTy to wpisujemy:
    reset halt

    Podstawowe użycie toolchain'a arm-none-eabi czyli co się dzieje przed main

    odpalamy nowy terminal i przechodzimy tam gdzie zbudowaliśmy projekt. Odpalamy teraz gdb z argumentem do pliku .elf:
    arm-none-eabi-gdb blink.elf
    W terminalu wklepujemy taką o to sekwencję:
    target remote localhost:3333
    monitor reset halt
    load

    Podstawowe użycie toolchain'a arm-none-eabi czyli co się dzieje przed main

    Gratuluje, możemy debugować. Wszelakie komendy potrzebne do debuggowania z terminalu można znaleźć w sieci. Niestety nie ma możliwości używania gdbtui pod windowsem :(

    Podstawowe użycie toolchain'a arm-none-eabi czyli co się dzieje przed main



    Powyższe przykład służy jedynie do uświadomienia jak wiele dzieje się jeszcze przed uruchomieniem funkcji „main”. Nie jest to rozwiązanie, które można stosować w poważnych projektach, ale mam nadzieję że posłuży jako pewien punkt podparcia w poszukiwaniu dalszej wiedzy na temat rozpoczynania projektów „from scratch”.

    Dodatkowe materiały:
    https://www.embedded.com/design/mcus-processors-and-socs/4007119/Building-Bare-Metal-ARM-Systems-with-GNU-Part-1--Getting-Started

    https://community.arm.com/processors/b/blog/posts/useful-assembler-directives-and-macros-for-the-gnu-assembler

    http://www.bravegnu.org/gnu-eprog/lds.html

    http://pandafruits.com/stm32_primer/stm32_primer_minimal.php

    Cool? Ranking DIY
    About Author
    _lazor_
    Moderator of Designing
    Offline 
    Materiały video na temat energoelektroniki:
    https://www.youtube.com/user/sambenyaakov/videos
    Has specialization in: Programista embedded/ elektrotechnik
    _lazor_ wrote 3632 posts with rating 1055, helped 247 times. Live in city Wrocław. Been with us since 2016 year.
  • NDN
  • #2
    chudybyk
    Level 31  
    Dla całkiem niezorientowanych i próbujących zrobić pierwszy projekt warto dodać, że większość powyższych czynności można przykryć zgrabnym środowiskiem. Na forum było parę przykładów zastosowania Eclipse C++. Do Eclipse proponuję plugin https://gnu-mcu-eclipse.github.io/ i początek jest nieco łatwiejszy, bo plugin wygeneruje makefile, startupy, oraz skrypty linkera. Wadą jest co prawda wrzucanie na siłę starych bibliotek STD od ST, ale da się je wyrzucić i programować bez tego "pakietu szczęścia". Ewentualnie można kombinować z STM32_CUBE i męczyć się ze "szczęściem do kwadratu".
    Na pewno warto pobawić się tym pluginem i podejrzeć jak zmieniają się pliki konfiguracyjne i parametry kompilacji w zależności od wyklikanej opcji.
  • #3
    Janusz_kk
    Level 37  
    I to jest przykład dlaczego zostanę nadal przy avrstudio i avr-ach, bo 8 bitów mi wystarczy, a do większych obliczeń zastosuję jakieś pi lub orange,
    bo niestety ale nie przekonałeś mnie do arm-ów.
  • NDN
  • #4
    _lazor_
    Moderator of Designing
    Raspberry pi to już jest ARM + GPU od brodcom ;) a ten artykuł został właśnie natchniony pisaniem bare metal pod raspberry pi :)

    Tak więc ja Ciebie nie musiałem namawiać nawet :)
  • #5
    simw
    Level 26  
    Janusz_kk wrote:
    I to jest przykład dlaczego zostanę nadal przy avrstudio i avr-ach, bo 8 bitów mi wystarczy, a do większych obliczeń zastosuję jakieś pi lub orange,
    bo niestety ale nie przekonałeś mnie do arm-ów.

    Dobrze byłoby pisząc takie coś podać jakieś argumenty, czy przykłady, bo tak tylko siejesz niepotrzebny zamęt. Z Twojej wypowiedzi zupełnie nic nie wynika. Co Ciebie nie przekonało do arm'ów? To, że procedura startowa wymaga zrozumienia? Czy to, że użytkownik sam może sobie stworzyć własną procedurę startową?
    Mnie do STM32 przekonało kilka spraw:

    - dojrzałe, gotowe środowiska programistyczne, które można zainstalować i uruchomić pierwszy, działający program w ciągu dosłownie 5 minut,

    - niezliczona ilość tanich płytek deweloperskich, można wybierać do woli, większość z nich wyposażona od razu w programator i debugger,

    - unifikacja programowania wielu rodzin procesorów, łatwa przenośność kodu - pomiędzy niektórymi rodzinami wystarczy w wielu przypadkach tylko uruchomić właściwy szablon i skopiować kody, by przenieść program na wydajniejszy uK,

    - banalny już wydaje mi się argument, że zwykle za "tę samą" cenę mamy uK wydajniejszy, bogatszy w peryferia - ten argument często jest negowany przez użytkowników 8 bitowców, nie wiem w sumie dlaczego,

    - dostępne na "stoku" zaawansowane biblioteki do obsługi stosu USB i ETH - jeszcze nie miałem potrzeb w tej dziedzinie, ale z łatwością uruchamiałem urządzenia HID czy też symulator portu COM, na płytkach deweloperskich za 2 dolary,

    - dostępny od razu bez kombinacji zaawansowany debugger - kiedyś go nie doceniałem, wystarczała mi dioda, ale teraz nie wyobrażam sobie pracy bez debuggera - mocno ułatwia pracę,

    - priorytetyzacją przerwań czy kontroler DMA,

    - środowisko CubeMX (Cube) zdecydowanie ułatwia pracę, podczas analizy potrzeb projektowych,

    - darmowa, łatwo zrozumiała w użytkowaniu biblioteka DSP, pierwszy działający pseudo analizator widma uruchomiłem w pierwszym tygodniu nauki programowania.


    Sam nie jestem zawodowcem, dłubię sobie w uK wieczorami, robiąc różne mniej lub bardziej potrzebne gadżety, orłem w C nie jestem, pomimo tego obecnie RM na 1300 stron nie robi już na mnie wrażenia. Potrafię się w nim dość swobodnie poruszać, co nie oznacza, że wszystko rozumiem - wręcz przeciwnie. Polecam wszystkim "przejście" na arm'y - nie ma co się ograniczać do 8 bit.
    Jest szybko, wygodnie, mam nadzieję, że perspektywicznie, dodatkowo mamy całkiem szczegółową dokumentację - do tej pory nawet nie musiałem zaglądać do errat - pewnie jeszcze to przede mną.

    Przepraszam, że być może trochę nie na temat, ale uznałem, że "niejasny" zarzut Janusza_kk wymaga stanowczej reakcji :)

    PS
    Nie rozumiem jak można się tak katować zostając przy takim starociu jak avrstudio :) To środowisko przy eclipse to jak ubogi krewny zza morza :) Jeszcze można by się zastanawiać nad Atmel Studio, ale ten pierwszy?

    Dodano po 30 [minuty]:

    _lazor_ wrote:
    6. Debugowanie
    Ważne! Kompilator musi budować z flagą -g !


    Dlaczego musi? Jakby to odnieść do gotowych środowisk, w którym sam sobie dłubię, gdzie wg mojej wiedzy opcja "-Og" bardzo często "szkodzi" w poprawnym debugowaniu, to raczej lepiej debugować z opcją "-O0" - mam nadzieję, że nie pomyliłem pojęć - wydaje mi się że chodzi o opcje optymalizacyjne kompilatora.
    Skąd moje pytanie? Wg mojego doświadczenia z TrueStudio, czy System Workbench - lepiej się debugguje właśnie bez optymalizacji kodu - bo każda optymalizacja, łącznie z "-Og" tylko utrudnia analizę - praca krokowa powoduje niezrozumiałe dla mnie "skoki", że tak powiem kursora.
    Być może mam źle skonfigurowane OCD, ale działam na domyślnych ustawieniach środowisk.
  • #6
    _lazor_
    Moderator of Designing
    simw wrote:
    _lazor_ wrote:
    6. Debugowanie
    Ważne! Kompilator musi budować z flagą -g !


    Dlaczego musi? Jakby to odnieść do gotowych środowisk, w którym sam sobie dłubię, gdzie wg mojej wiedzy opcja "-Og" bardzo często "szkodzi" w poprawnym debugowaniu, to raczej lepiej debugować z opcją "-O0" - mam nadzieję, że nie pomyliłem pojęć - wydaje mi się że chodzi o opcje optymalizacyjne kompilatora.
    Skąd moje pytanie? Wg mojego doświadczenia z TrueStudio, czy System Workbench - lepiej się debugguje właśnie bez optymalizacji kodu - bo każda optymalizacja, łącznie z "-Og" tylko utrudnia analizę - praca krokowa powoduje niezrozumiałe dla mnie "skoki", że tak powiem kursora.
    Być może mam źle skonfigurowane OCD, ale działam na domyślnych ustawieniach środowisk.


    Niestety pomyliłeś się, to o czym piszesz to optymalizacja, której w przykładzie który podałem w ogóle nie ma (wartość defaultowa).
    Opcja -g dla kompilatora oznacza:
    "Produce debugging information in the operating system’s native format (stabs, COFF, XCOFF, or DWARF). GDB can work with this debugging information. "

    https://gcc.gnu.org/onlinedocs/gcc/Debugging-Options.html#Debugging-Options

    Opcje związane z optymalizacją możesz znaleźć pod tym linkiem:

    https://gcc.gnu.org/onlinedocs/gcc/Optimize-Options.html#Optimize-Options
  • #7
    simw
    Level 26  
    _lazor_ wrote:
    Niestety pomyliłeś się, to o czym piszesz to optymalizacja, której w przykładzie który podałem w ogóle nie ma (wartość defaultowa).

    No tak za plecami czułem, że chodzi o opcje debugowania, ale z rozpędu nie sprawdziłem.
    W System Worbench mamy przecież:
    Podstawowe użycie toolchain'a arm-none-eabi czyli co się dzieje przed main

    Dzięki za linki poczytam do poduszki :)
  • #8
    _lazor_
    Moderator of Designing
    Teraz w sumie przetestowałem jak kod będzie działał z -O3 i co ciekawe kompilator chce kod zoptymalizować poprzez użycie memset i memcpy, których z faktu nie używania standardowych bibliotek nie mamy. Rozwiązaniem na taki problem jest dodanie opcji kompilatora -ffreestanding.

    Rozmiar kodu maleje prawie dwukrotnie a sama dioda mruga znacząco szybciej (z faktu, że delay jest zrobiony na instrukcjach "nope").



    Trzeba również pamiętać, że co firma czy IDE używa trochę innych narzędzi i flagi kompilatora, assemblera i linkera mogą się znacząco różnić.
  • #9
    vp32
    Level 11  
    Możecie choć odrobinę rozwinąć wątek z "miękkim resetem".
    Pierwszy raz się z tym określeniem spotkałem i zaciekawiło mnie o co chodzi, jak się wywołuje i może gdzie jest opisany np dla STM32?
  • #10
    _lazor_
    Moderator of Designing
    Ogólnie wychodzi na to, że pomieszałem informacje z cortex-M z cortex-A. W wypadku cortex-M wygląda na to, że zawsze następuje ściągnięcie wewnętrzne Vdd do GND i uruchomienie uC od nowa.

    Co do cortex-A przedstawię trochę informacji wieczorem w tym poście.
    A jak na razie o co chodzi z hard i soft resetem:
    https://en.wikipedia.org/wiki/Reboot
  • #11
    vp32
    Level 11  
    _lazor_ wrote:
    A jak na razie o co chodzi z hard i soft resetem:
    https://en.wikipedia.org/wiki/Reboot

    Wiesz tym nie wyjaśniłeś jak się to ma do STM32. Jak to zrealizować i dlaczego po tym miękkim resecie program uruchamia się od adresu 0x00000004
  • #12
    _lazor_
    Moderator of Designing
    Na cortex-m jest możliwość wykrycia źródła resetu, ale kod będzie zawsze startować z adresu 0x00000000, nawet jeśli wczesniej VTOR był ustawiony na inną wartość (nawet software reset powoduje ustawienie default wartości dla rejestrów, oprócz rejestrów RCC).

    Tak więc podałem błędną informację w artykule, którą poprawiłem.
  • #13
    vp32
    Level 11  
    Ok dzięki, nie zauważyłem korekty i dalej miałem w myślach to co wyczytałem. :D
  • #14
    Bojleros
    Level 16  
    Jeżeli idzie o udokumentowanie tej wiedzy to artykuł jest super. Sam się kiedyś kopałem z tego typu ustawieniami ale to były czasy gdy IDE pod ARM można było albo kupić albo poskładać samemu z ogólnodostępnych kawałków (pomijam te z ograniczeniem na rozmiar kodu). Zawsze było to lekko bolesne ale obecnie chyba przynajmniej dla ST nie ma już tego problemu bo jest AC6.
  • #15
    Atlantis86
    Level 19  
    Janusz_kk wrote:
    I to jest przykład dlaczego zostanę nadal przy avrstudio i avr-ach, bo 8 bitów mi wystarczy, a do większych obliczeń zastosuję jakieś pi lub orange,
    bo niestety ale nie przekonałeś mnie do arm-ów.


    Przecież nikt Ci nie każe obsługiwać STM-ów w sposób niskopoziomowy. Równie dobrze możesz skorzystać z CubeMX, jakiegoś wygodnego IDE oraz bibliotek HAL. Wówczas nawet nie będziesz musiał wiedzieć, że coś takiego jak Makefile albo skrypt linkera w ogóle istnieje. To działa też w drugą stronę - gdybyś chciał, w podobny sposób na niskim poziomie mógłbyś pisać na AVR-y.

    Powielasz znany mit, jakoby mikrokontrolery ośmiobitowe były łatwiejsze od współczesnych 32bitowych. A nie są. Wręcz przeciwnie. Programując AVR-y zwykle musisz odwoływać się bezpośrednio do rejestrów. W przypadku większości nowoczesnych układów, ze względu na rozbudowany charakter sprzętu byłoby to w większości przypadków zbyt kłopotliwe (choć rzecz jasna możliwe), więc producenci udostępniają wygodne biblioteki, potrafiące konfigurować i obsługiwać peryferia w bardziej naturalny, "ludzki" sposób.

    Poza tym specyfika 8bitowych układów też powoduje występowanie pułapek, których nie ma na nowocześniejszych układach - jak chociażby konieczność wyłączania przerwań w przypadku tych operacji na zmiennych, które nie są w stanie wykonać się w ciągu jednego cyklu.

    Komputery jednopłytkowe w stylu RasPi nie zawsze są dobrą alternatywą dla mikrokontrolerów. Ich ponowne uruchomienie po restarcie wymaga zasilania, odłączenie zasilania bez zamknięcia systemu może generować problemy, pomimo sporego procesora szybkość operacji jest ograniczona z uwagi na konieczność obsługi rozbudowanego systemu operacyjnego.
  • #16
    _lazor_
    Moderator of Designing
    Atlantis86 wrote:
    Powielasz znany mit, jakoby mikrokontrolery ośmiobitowe były łatwiejsze od współczesnych 32bitowych. A nie są. Wręcz przeciwnie. Programując AVR-y zwykle musisz odwoływać się bezpośrednio do rejestrów. W przypadku większości nowoczesnych układów, ze względu na rozbudowany charakter sprzętu byłoby to w większości przypadków zbyt kłopotliwe (choć rzecz jasna możliwe), więc producenci udostępniają wygodne biblioteki, potrafiące konfigurować i obsługiwać peryferia w bardziej naturalny, "ludzki" sposób.

    To nie tak że nie odwołujesz się do rejestrów w cortex-m, po prostu jest to ukryte pod definicjami, które są bardziej opisowe, jednak to nadal są rejestry.
    Same biblioteki są wygodne, ale do czasu gdy chce się zrobić coś bardziej złożonego, wtedy i tak trzeba znać jak to działa i pisać samemu. Tutaj nie ma różnicy między AVR a ARM.

    Atlantis86 wrote:
    Poza tym specyfika 8bitowych układów też powoduje występowanie pułapek, których nie ma na nowocześniejszych układach - jak chociażby konieczność wyłączania przerwań w przypadku tych operacji na zmiennych, które nie są w stanie wykonać się w ciągu jednego cyklu.

    Nadal w kodzie krytycznym należy wyłączać przerwania i nadal są instrukcje które nie wykonują się w jednym cyklu.

    Atlantis86 wrote:
    Komputery jednopłytkowe w stylu RasPi nie zawsze są dobrą alternatywą dla mikrokontrolerów. Ich ponowne uruchomienie po restarcie wymaga zasilania, odłączenie zasilania bez zamknięcia systemu może generować problemy, pomimo sporego procesora szybkość operacji jest ograniczona z uwagi na konieczność obsługi rozbudowanego systemu operacyjnego.

    Nie trzeba używać systemu operacyjnego aby pisać na raspberry pi :)
  • #17
    Atlantis86
    Level 19  
    _lazor_ wrote:

    To nie tak że nie odwołujesz się do rejestrów w cortex-m, po prostu jest to ukryte pod definicjami, które są bardziej opisowe, jednak to nadal są rejestry.
    Same biblioteki są wygodne, ale do czasu gdy chce się zrobić coś bardziej złożonego, wtedy i tak trzeba znać jak to działa i pisać samemu. Tutaj nie ma różnicy między AVR a ARM.


    To jest jasne. Niemniej punkt wejścia jest niższy, właśnie z uwagi na to, że korzystanie z tych definicji jest bardziej intuicyjne od bezpośredniego pisania po rejestrach. Po prostu dyskutuję z mitem, że powinno się zaczynać od procesorów ośmiobitowych, jako tych łatwiejszych.
    Mówię to jako osoba, która parę lat temu zaczynała od AVR-ów, potem przerzuciła się na PIC32, teraz eksperymentuje z STM-ami. W międzyczasie z ciekawości zrobiłem też projekty na "antycznych" platformach w rodzaju 8051, Z80 czy 6502. Generalnie po jakimś czasie platforma przestaje mieć znaczenie, jeśli tylko jest dostępny kompilator trzymający się standardów.


    Quote:
    Nadal w kodzie krytycznym należy wyłączać przerwania i nadal są instrukcje które nie wykonują się w jednym cyklu.


    Niemniej takie sytuacje w przypadku 32-bitowych mikrokontrolerów są o wiele rzadsze. Na AVR-ach można było sobie pozwolić właściwie tylko w przypadku przypisywania wartości zmiennej ośmiobitowej. Nowoczesne procesory pozwalają nawet na manipulowanie bitami w jednym cyklu. Tak więc sytuacje w których można popełnić krytyczną pomyłkę zdarzają się rzadziej.

    Quote:
    Nie trzeba używać systemu operacyjnego aby pisać na raspberry pi :)


    Racja. Niemniej jeśli chodzi o pisanie pod "bare metal", to wsparcie ze strony środowiska jest znacznie większe w przypadku takich STM-ów, niż rozmaitych układów SoC, na których oparte są popularne komputerki jednopłytkowe.
  • #18
    _lazor_
    Moderator of Designing
    Atlantis86 wrote:
    Quote:
    Nie trzeba używać systemu operacyjnego aby pisać na raspberry pi :)


    Racja. Niemniej jeśli chodzi o pisanie pod "bare metal", to wsparcie ze strony środowiska jest znacznie większe w przypadku takich STM-ów, niż rozmaitych układów SoC, na których oparte są popularne komputerki jednopłytkowe.


    Pichci się już bliźniaczy artykuł dla maliny bare metal :) Cortex-A to już jest zdecydowanie inny świat niż cortex-m, ale warto i nimi się zainteresować bo nadal dokumentacja dostarczona przez ARM jest bardzo dobra, gorzej z dokumentacją o samym SoC...
  • #19
    _jta_
    Electronics specialist
    2.dyrektywa .thumb_func mówi assemblerowi (as) że następny symbol wskazuje na instrukcje thumb

    O ile się orientuję, .thumb_func powoduje, że symbol oznaczający nazwę funkcji ma wartość o 1 większą od jej adresu (czyli nieparzystą - adresy kodu są parzyste). I dotyczy to nie tylko następnej funkcji, ale wszystkich funkcji po tej dyrektywie.

    Dzięki temu, jeśli ten symbol zostanie użyty jako adres skoku, do najniższego bitu PC (program counter) zostanie załadowane 1, co oznacza wykonywanie instrukcji w trybie Thumb. Ale nie jest to robione przez dowolną instrukcję - tylko niektóre instrukcje mają prawo ładować ten bit w PC (inne zachowują taki, jaki był); mają do tego prawo np. instrukcje BX, BLX (skok do adresu z rejestru; BLX to skok z zapamiętaniem adresu powrotu w rejestrze LR), oraz - co akurat w wektorze wyjątków/przerwań jest szczególnie istotne - obsługa wyjątków/przerwań - użycie tam parzystego adresu oznaczałoby, że wyjątek, bądź przerwanie spróbuje wykonywać instrukcje w trybie ARM, którego Cortex-M3 (to chyba jest architektura ARMv6-M) nie ma, więc się zawiesza.

    Jeśli procesor potrafi wykonywać instrukcje w obu trybach, to można w ramach jednego programu je łączyć - w szczególności, wyjątki i przerwania mogą być obsługiwane w różnych trybach, przy powrocie procesor wróci do poprzedniego trybu - ale utrudnieniem będzie fakt, że BL (wywołanie funkcji) nie może zmienić trybu, trzeba używać BLX (albo BX).
  • #20
    _lazor_
    Moderator of Designing
    https://sourceware.org/binutils/docs-2.15/as/ARM-Directives.html

    "This directive specifies that the following symbol is the name of a Thumb encoded function. This information is necessary in order to allow the assembler and linker to generate correct code for interworking between Arm and Thumb instructions and should be used even if interworking is not going to be performed. The presence of this directive also implies .thumb"

    Oczywiście w powyższym kodzie jest to zbędne, gdyż cortex-m nie wspiera zestawu instrukcji ARM. Cortex-m to przegląd rdzeni od ARMv6-M do ARMv8 w najbliższej przyszłości (od ST będzie to seria STM32L5 z m33).

    Oczywiście dziękuję za merytoryczną uwagę i jeśli coś jeszcze zauważysz lub nie jesteś pewny poprawności to pisz śmiało, z wielką chęcią przedyskutuje problem.
  • #21
    _jta_
    Electronics specialist
    Oczywiście w powyższym kodzie jest to zbędne

    To nie jest zbędne, przeciwnie, jest konieczne, jeśli nazwa ma być użyta do wygenerowania 32-bitowego adresu funkcji - fakt, że procesor ma tylko instrukcje Thumb nie oznacza, że można bezkarnie załadować do PC parzysty adres - powoduje to zawieszenie procesora, sprawdzałem.

    Ja używałem takiej konstrukcji, i to działało:
    Code: text
    Log in, to see the code

    - wszystkie funkcje zdefiniowane przez _func miały nieparzyste adresy.

    Z tym, że problem z (nie)parzystością adresu ujawnia się tylko wtedy, gdy instrukcja używa adresu w postaci liczbe 32-bitowej - instrukcje zawierające adres względny nie kodują najniższego bitu adresu i zachowują najniższy bit PC.
  • #22
    _lazor_
    Moderator of Designing
    Tak pomyliłem się i masz rację co do .thumb_func. Jest to wielce pomocna uwaga _jta_
  • #23
    Janusz_kk
    Level 37  
    Atlantis86 wrote:
    Powielasz znany mit, jakoby mikrokontrolery ośmiobitowe były łatwiejsze od współczesnych 32bitowych. A nie są.

    Żaden mit, oczywiście że są łatwiejsze do opanowania, jest więcej materiałów poza tym konieczność sięgnięcia po 32 bity
    w prostych sterownikach bez ekranu graficznego sięga 0%.
  • #24
    _lazor_
    Moderator of Designing
    Chciałbym aby tezę podpierać argumentami, najlepiej technicznymi. Argumenty z piaskownicy nie będą tolerowane.
  • #25
    chudybyk
    Level 31  
    Janusz_kk wrote:
    konieczność sięgnięcia po 32 bity
    w prostych sterownikach bez ekranu graficznego sięga 0%

    Coś takiego. To ja chyba błąd robię, że tam gdzie poprzednio używałem AVR-ków, teraz ładuję Cortexy M0. Są tańsze i równie dobre, a nieraz lepsze.
    Szerokość słowa nie ma większego znaczenia dla łatwości programowania. Dla mnie wzorem przyjaznej konstrukcji rdzenia jest seria Motoroli MC68000. Przejrzysta lista rozkazów, bardzo uniwersalny zestaw rejestrów, ciągła pamięć, itp., kodowanie tego w asemblerze to przyjemność.
    Kto jednak bawi się dzisiaj asemblerem? Programuje się mikrokontrolery w C lub nawet C++, mając gdzieś budowę CPU. Myślę, że entuzjastów 8-bitowców przekonuje niski stopień skomplikowania peryferiów, a nie samego rdzenia. W Cortexach trzeba trochę doczytać o ustawieniu taktowania, powłączać bloki funkcjonalne peryferiów, albo użyć DMA. Diabeł rogaty jest milszy a jeżozwierz przytulniejszy! ;-)
    Na zgodę napiszę, że gdyby 8-bit miało swoje uzasadnienie ekonomiczne, to jeszcze bym znalazł dla nich zastosowanie, ale na to się nie zanosi.
  • #26
    _lazor_
    Moderator of Designing
    Jeśli popatrzymy na obudowy to faktycznie 8bit architektury mają dużego plusa, gdyż można dostać naprawdę malutkie obudowy, których nie uświadczymy przy cortex-M czy innych 32bit architekturach.

    Jednak, byłem świadkiem gdy pewna firma robiła układ regulacji temperatury w domu i użyła... cortex-A z linuksem... Niestety rozwiązania będą iść w tym kierunku, niż w najoptymalniejsze...
  • #27
    _jta_
    Electronics specialist
    Zdaje się, że jeśli chodzi o moduły, to jakieś Arduino mogą od razu być programowane poprzez USB; co tańsze STM32 wymagają przejściówek, np. USB na UART TTL, albo RS-232 na UART TTL, albo USB na SWD. Z tego chyba RS-232 na UART TTL można łatwo zrobić, ale jest to dodatkowa robota, żeby móc zacząć. Moduł STM32F103C8T6, który jest konkurencyjny cenowo z klonami Arduino, ma wprawdzie USB, ale jego bootloader działa tylko z USART1 - trzeba mu wgrać bootloader USB do flasha.
  • #28
    _lazor_
    Moderator of Designing
    Nie jest to prawda, boardy od ST mają po prostu na pokładzie STLINK, który jest debuggerem i programatorem. Ma wystawione JTAG i SWD, więc można z niego korzystać również do własnoręcznie wykonanych układów (jest szansa odłamania STLINK i z niego korzystać całkowicie osobno).

    Arduino to jakiś twór z otoczką a nie konkretna architektura rdzenia. ST wypuszcza boardy z konkretnymi układami, bez zbędnej otoczki. Oczywiście nie mówię, że to jedyny słuszny producent dla cortex-m, są w końcu jeszcze NXP z swoimi kinetis, TI z swoimi lunchpad'ami czy Infineon z XMC (patrz XMC 2Go).
  • #30
    _lazor_
    Moderator of Designing
    Ceny na szybko z kamami
    STM32L100C-DISCO - 39zł
    XMC 2Go - 40zł
    NUCLEO-L432KC- 49zł
    STM32F3348 - 80zł (a posiada wszystko co trzeba by zacząć zabawę z energoelektroniką)

    Może dla kogoś 20zł robi różnice, dla to jest to pomijalne.