Cuprins:

Partea 1 Asamblarea brațului TI RSLK Robotics Learning Curriculum Lab 7 STM32 Nucleo: 16 Etape
Partea 1 Asamblarea brațului TI RSLK Robotics Learning Curriculum Lab 7 STM32 Nucleo: 16 Etape

Video: Partea 1 Asamblarea brațului TI RSLK Robotics Learning Curriculum Lab 7 STM32 Nucleo: 16 Etape

Video: Partea 1 Asamblarea brațului TI RSLK Robotics Learning Curriculum Lab 7 STM32 Nucleo: 16 Etape
Video: Raspberry Pi Pico for Robotics 2024, Iulie
Anonim
Image
Image

Accentul acestui instructabil este microcontrolerul STM32 Nucleo. Motivația pentru aceasta pentru a putea crea un proiect de asamblare din oase goale. Acest lucru ne va ajuta să aprofundăm și să înțelegem proiectul MSP432 Launchpad (TI-RSLK) care a făcut deja obiectul mai multor instrumente instructabile.

Nu există prea mult ajutor online pentru a crea un proiect numai pentru asamblare pentru MSP432, utilizând Studio Composer Studio. Până în prezent tocmai am copiat / lipit dintr-un proiect de asamblare preexistent. Această abordare ne-a servit bine.

Cu toate acestea, acum, pentru Lab 7, am întâmpinat o problemă. Sau cel puțin un sughiț temporar. Lab 7 introduce mașini cu stări finite, iar primul lucru pe care îl întâlnim este nevoia de a crea și utiliza o serie de valori. Deoarece cursul TI utilizează în principal programarea C - aceasta nu este o problemă. Dar aceste instructabile s-au concentrat pe asamblare, nu pe C.

Mai mult, întrucât matricea are valori numai în citire, ar fi bine să o puneți în memoria flash, nu în RAM.

Se pare că există mult mai mult ajutor online pentru proiectele de asamblare care utilizează MCU STM32, astfel, începem cu acest instructabil, cu scopul de a folosi ceea ce se învață, pentru a aplica apoi la MSP432 și la Code Composer Studio.

Pe drumul către acest obiectiv, vom avea și experiență cu încă un alt microcontroler popular.

Pasul 1: Test inițial al dispozitivului

Testul inițial al dispozitivului
Testul inițial al dispozitivului
Testul inițial al dispozitivului
Testul inițial al dispozitivului
Testul inițial al dispozitivului
Testul inițial al dispozitivului

Din nou, de ce să alegem STM32 Nucleo în special?

Sincer? Pentru că am căutat articole bune despre proiecte de asamblare bare-metal pentru controlere ARM și am dat peste această serie. Și, de asemenea, pentru că STM32 pare a fi un MCU popular.

Am făcut unele cercetări (există o mulțime de versiuni dintre care puteți alege - a se vedea imaginea de mai sus), dar în cele din urmă a devenit ce pot obține de fapt, deoarece aveam să folosesc Amazon (în SUA).

Vine într-un pachet simplu, dar profesional, cu câteva instrucțiuni de pornire. A fost cam amuzant să vedem că demo-ul ars în controler era aproape exact ceea ce am făcut în Instructables din trecut - un LED clipește și schimbă viteza în funcție de apăsarea unui buton.

Se pare că această placă de dezvoltare este foarte asemănătoare cu MSP432 prin faptul că există 2 LED-uri și un buton de utilizator. MSP432 are 2 butoane de utilizator.

După cum puteți vedea în fotografii, am fost puțin surprins de faptul că placa are un mini și nu un micro USB. A trebuit să fugă să cumpăr un cablu.

Un alt test bun este că atunci când îl conectați la computer (folosesc o cutie Linux), acesta apare în managerul meu de fișiere, ca sistem de fișiere, numit „NODE_F303RE”. Deschidere care dezvăluie două fișiere, unul HTML și unul text.

Gata, dar cel puțin se spune că conectivitatea pare destul de ușoară.

Acum suntem gata să începem.

Voi încerca să nu repet nicio informație bună din seria de articole IVONOMICON Bare Metal, ci mai degrabă să o completez.

Pasul 2: Elementele esențiale

Primul lucru de care avem nevoie este un compilator.

Și apoi, avem nevoie de un depanator:

devchu @ chubox: ~ $ sudo apt-get install gdb-arm-none-eabiCitirea listelor de pachete … Gata Construirea arborelui de dependență Citirea informațiilor despre starea … Gata Următoarele pachete NOI vor fi instalate: gdb-arm-none-eabi 0 actualizat, 1 nou instalat, 0 pentru eliminare și 8 neactualizate. Trebuie să obțineți 2, 722 kB de arhive. După această operație, vor fi folosiți 7, 738 kB de spațiu suplimentar pe disc. Obțineți: 1 https://us.archive.ubuntu.com/ubuntu xenial / universe amd64 gdb-arm-none-eabi amd64 7.10-1ubuntu3 + 9 [2, 722 kB] Fetched 2, 722 kB in 1s (1, 988 kB / s) Selectarea pachetului neselectat anterior gdb-arm-none-eabi. (Citirea bazei de date … 262428 de fișiere și directoare instalate în prezent.) Pregătirea pentru despachetare … / gdb-arm-none-eabi_7.10-1ubuntu3 + 9_amd64.deb … Despachetarea gdb-arm-none-eabi (7.10-1ubuntu3 + 9) … Procesare declanșatoare pentru man-db (2.7.5-1) … Configurarea gdb-arm-none-eabi (7.10-1ubuntu3 + 9) …

Pasul 3: Elementele esențiale - Windows

Pasul de mai sus presupunea că folosim Linux. Ce se întâmplă dacă folosim Windows?

Puteți accesa site-ul braț pentru dezvoltatori și există mai multe opțiuni de descărcare disponibile. Folosesc un aparat Windows 8.

În timpul instalării, am ales să îl instalez pe unitatea rădăcină „C: \” în loc de Fișiere de program doar pentru că folosesc și cygwin și a fost mai ușor să creez o legătură din coșul meu local către un folder rădăcină C: decât toate încurcați-vă în calea către Fișiere de program (cu spații, etc).

Astfel, mediul și calea mea cygwin, etc., arată așa:

C: / cygwin64 / home / bin / arm-none-eabi-gcc, unde arm-none-eabi-gcc este un link către C: / GNUToolsArmEmbedded / 7.2018.q2.update / bin / arm-none-eabi- gcc.

Apoi am creat un folder „dev” sub cygwin home, și acolo am plasat fișierul core. S și am rulat comanda compilatorului. (a se vedea mai jos pentru lucrurile despre compilator).

Am făcut exact același lucru pentru gdb (arm-none-eabi-gdb).

Pasul 4: Care sunt elementele esențiale

Deci, ce este „gcc-arm-none-eabi”?

Compilatorul GNU (GCC) va compila limbaje de programare (cum ar fi C) în codul nativ pentru mașina pe care rulează. De exemplu, dacă ar fi să compilați un cod C folosind GCC pe computerul dvs. Windows, acesta ar fi construit pentru a rula pe computerul Windows. Executabilul generat nu va rula (de obicei) pe microcontrolerul ARM.

Deci, pentru a construi programe care să fie descărcate și arse în microcontrolerul ARM (în cazul nostru actual care ar fi STM32 Nucelo), trebuie să oferim GCC altceva: capacitatea de a „compila încrucișat”. Adică abilitatea de a genera un executabil, nu pentru sistemul său nativ (și procesor), ci pentru sistemul țintă (microcontrolerul ARM). Acolo intră în joc „gcc-arm-none-eabi”.

Deci, ce este „gdb-arm-none-eabi”?

Odată ce am descărcat și am ars (intermitent) executabilul nou generat în microcontroler, probabil că vom dori să-l depanăm - pas cu linie cu linie a codului. GDB este depanatorul gnu și, de asemenea, are nevoie de o modalitate de a-și face treaba, dar care vizează un alt sistem.

Astfel, gdb-arm-none-eabi este pentru GDB, ceea ce este gcc-arm-none-eabi pentru GCC.

O altă instalare sugerată a fost „libnewlib-arm-none-eabi”. Ce este acela?

Newlib este o bibliotecă C și o bibliotecă matematică destinată utilizării pe sisteme încorporate. Este un conglomerat de mai multe părți ale bibliotecii, toate sub licențe de software gratuit care le fac ușor de utilizat pe produsele încorporate.

Și în cele din urmă, pachetul „libstdc ++ - arm-none-eabi”. Asta e destul de evident; este biblioteca C ++ pentru cross-compiler; pentru microcontrolere ARM încorporate.

Pasul 5: fișierul Linker

Fișierul Linker
Fișierul Linker
Fișierul Linker
Fișierul Linker

Să creăm un script linker.

O parte sau bloc cheie din acest fișier ar fi comanda MEMORY.

--- de la sourceware.org:

Configurarea implicită a linkerului permite alocarea întregii memorii disponibile. Puteți suprascrie acest lucru utilizând comanda MEMORY. Comanda MEMORY descrie locația și dimensiunea blocurilor de memorie din țintă. Îl puteți utiliza pentru a descrie ce regiuni de memorie pot fi utilizate de linker și ce regiuni de memorie trebuie să evite. Apoi puteți atribui secțiuni anumitor regiuni de memorie. Linkerul va seta adresele secțiunilor pe baza regiunilor de memorie și va avertiza despre regiunile care devin prea pline. Linker-ul nu va amesteca secțiunile pentru a se încadra în regiunile disponibile. Un script linker poate conține multe utilizări ale comenzii MEMORY, cu toate acestea, toate blocurile de memorie definite sunt tratate ca și cum ar fi fost specificate într-o singură comandă MEMORY. Sintaxa pentru MEMORY este:

MEMORIE

{nume [(attr)]: ORIGINĂ = origine, LUNGIME = len …}

Exemplul din articol:

/ * Definiți sfârșitul memoriei RAM și limita memoriei stivei * // * (4KB SRAM pe linia STM32F031x6, 4096 = 0x1000) * / / * (RAM începe la adresa 0x20000000) _stack = 0x20001000;

MEMORIE

{FLASH (rx): ORIGINĂ = 0x08000000, LUNGIME = 32K RAM (rxw): ORIGINĂ = 0x20000000, LUNGIME = 4K}

Deci, trebuie să ne dăm seama cât de mult FLASH (pentru programul nostru și constante, etc) și cât de mult RAM (pentru a fi folosit de program; heap și stivă, etc) pentru placa noastră specială. Acest lucru devine puțin interesant.

Micul card plăcut care vine cu Nucleo spune că are memorie flash este de 512 Kbytes, iar SRAM este de 80 Kbytes. Cu toate acestea, conectându-l la USB, acesta este montat ca un sistem de fișiere cu două fișiere, iar atât managerul de fișiere, cât și GParted indică faptul că are peste 540 de Kbyte de spațiu. (RAM?).

DAR, încercând să ștergeți cele două fișiere folosind managerul de fișiere, deconectând apoi reconectând dispozitivul, afișează în continuare cele două fișiere. (și managerul de fișiere a recunoscut ceva deoarece există o mică pictogramă „blocare” pe fiecare fișier.

Deci, să mergem cu cifrele de pe card. Deci, acum luăm exemplul de mai sus și îl convertim la placa noastră specifică.

Poate doriți să utilizați ceva de genul acestui convertor de memorie online, pentru a trece de la KB general la un anumit număr de octeți.

Apoi poate doriți să utilizați un convertor zecimal online în hex.

/ * Definiți sfârșitul memoriei RAM și limita memoriei stivei * /

/ * (4KB SRAM pe linia STM32F031x6, 4096 = 0x1000) * // * exemplul * /

/ * pasul 1: (80KB SRAM pe STM32F303RE, 81920 = 0x14000) * // * placa noastră * /

/ * pasul 2, adăugați dimensiunea hexagonală la adresa de pornire hexagonală (mai jos). * /

/ * (RAM începe la adresa 0x20000000) * /

_stack = 0x20001000; /* exemplul */

_stack = 0x20014000; / * consiliul nostru * /

MEMORIE {

FLASH (rx): ORIGINĂ = 0x08000000, LUNGIME = 512K

RAM (rxw): ORIGINĂ = 0x20000000, LUNGIME = 80K

}

Să numim fișierul de mai sus „linker.script.ld”.

Pasul 6: Tabelul Vector

Tabelul Vector
Tabelul Vector

Acum vom crea un mic fișier de asamblare (cu directive) pentru a face o manipulare foarte simplă a întreruperilor. Vom urma exemplul articolului și vom crea fișierul numit „core. S”.

Din nou, iată exemplul conținutului fișierului, dar am făcut o modificare pentru placa noastră specifică:

// Aceste instrucțiuni definesc atributele cipului nostru și

// limbajul de asamblare pe care îl vom folosi:.syntax unified / * Vezi mai jos după această zonă de cod * / /*.cpu cortex-m0 * / / * comentează această linie a exemplului * /.cpu cortex-m4 / * adăugați în schimb cortexul consiliului nostru. vezi imaginea de mai sus în acest pas * / /*.fpu softvfp * / / * comentează această linie a exemplului * /.fpu vfpv4 / * adaugă în schimb placa noastră; are un FPU * /.thumb // Locații de memorie globală..global vtable.global reset_handler / * * Tabelul vectorului real. * Doar dimensiunea memoriei RAM și a handlerului „reset” sunt * incluse, pentru simplitate. * /.type vtable,% object vtable:.word _estack.word reset_handler.size vtable,.-vtable

Hmm.. Nici o directivă „.align”

Cu toate acestea, acest lucru nu este critic. Mai multe despre asta (poate) mai târziu.

.sintaxa unificată

.sintaxă [unificat | împărțit]

Această directivă stabilește sintaxa setului de instrucțiuni așa cum este descris în secțiunea ARM-Instruction-Set

9.4.2.1 Sintaxa setului de instrucțiuni Două sintaxe ușor diferite sunt compatibile cu instrucțiunile ARM și THUMB. Implicit, împărțit, folosește stilul vechi în care instrucțiunile ARM și THUMB aveau sintaxele lor, separate. Noua sintaxă unificată, care poate fi selectată prin directiva.syntax.

.fpu vfpv4

Compilatorul GCC poate produce binare cu mai multe opțiuni în ceea ce privește virgula mobilă: soft - potrivit pentru a rula pe CPU fără FPU - calculele se fac în software de către softfp generat de compilator - potrivit pentru a rula pe CPU cu sau fără FPU - va folosi o FPU dacă este prezent. Pentru cazul nostru specific (va trebui să vă faceți propriile cercetări), FPU-ul acestui tablou este conform cu vfpv4. Poate că va trebui să te joci cu asta. Sau chiar lăsați-l la softfp.

.thumb (vs.arm)

Aceste microcontrolere ARM au de fapt un amestec de seturi de instrucțiuni. Unul este ARM, altul este THUMB. O diferență este instrucțiunile pe 16 biți față de instrucțiunile pe 32 de biți. Astfel, această directivă îi spune compilatorului să trateze instrucțiunile ulterioare fie ca THUMB, fie ca ARM.

Vom lua doar restul fișierului așa cum este, deoarece aceste instructabile nu s-au adâncit încă în programarea ansamblului bazată pe întreruperi.

Pasul 7: Versiunea de asamblare a unui program „Hello World”

Următoarele pot intra și în fișierul „core. S” creat anterior. Acest lucru, din nou, provine din exemplul din articol.

/ * * Manipulatorul Reset. Apelat la resetare. * /.type reset_handler,% function reset_handler: // Setați indicatorul stivei la capătul stivei. // Valoarea „_stack” este definită în scriptul nostru linker. LDR r0, = _stack MOV sp, r0

// Setați câteva valori fictive. Când vedem aceste valori

// în depanatorul nostru, vom ști că programul nostru // este încărcat pe cip și funcționează. LDR r7, = 0xDEADBEEF MOVS r0, # 0 main_loop: // Adăugați 1 pentru a înregistra „r0”. ADĂUGĂ r0, r0, # 1 // Buclați înapoi. B main_loop.size reset_handler,.-Reset_handler

Deci, propulsia programului de mai sus este de a încărca un model recunoscut într-un registru MCU de bază (în acest caz R7) și o valoare de creștere începând de la zero într-un alt registru MCU de bază (în acest caz R0). Dacă parcurgem codul de executare, ar trebui să vedem creșterea datelor R0.

Dacă ați urmat împreună cu Instrucțiunile referitoare la cursurile / laboratoarele MSP432 și TI-RSLK, atunci aproape toate programele de mai sus ar trebui să vă fie familiare.

Singurul lucru nou pe care îl văd este utilizarea lui "=" la încărcarea "DEADBEEF" în înregistrarea R7. Nu folosisem asta.

Fișierul „core. S” atașat aici conține acum sursa completă.

Pasul 8: Compilarea codului

Este timpul să faceți câteva lucruri din linia de comandă. Ceva real, în cele din urmă.

Cu toate acestea, nu suntem chiar acolo. Din nou trebuie să modificăm comanda dată în articol și să o modificăm în funcție de situația noastră.

Iată exemplul de cod:

arm-none-eabi-gcc -x assembler-with-cpp -c -O0 -mcpu = cortex-m0 -mthumb -Wall core. S -o core.o

Dacă mergem pe site-ul gnu.org pentru GCC, (în acest caz versiunea 7.3),

X

-X este pentru a specifica limba. În caz contrar, dacă nu -x, atunci compilatorul va încerca să ghicească folosind extensia de fișier. (în cazul nostru, *. S).

Exemplul de mai sus din articol specifică assembler-with-cpp, dar am putea face doar assembler.

c

-C spune „compilați, dar nu conectați.

O0

-O este de a seta nivelul de optimizare. Utilizarea -O0 (oh-zero) spune „reduceți timpul de compilare și faceți ca depanarea să producă rezultatele așteptate. Aceasta este valoarea implicită”.

mcpu = cortex-m0

-Mcpu specifică numele procesorului țintă. În cazul nostru, ar fi cortex-m4.

mulțumire

-Mthumb specifică selectarea între generarea codului care execută stările ARM și THUMB.

Perete

-Peretele este, desigur, foarte comun și bine cunoscut. Activează toate semnalizatoarele de avertizare.

În cele din urmă, la sfârșitul comenzii avem fișierul de intrare core. S și fișierul de ieșire core.o.

Iată noua linie de comandă rezultată pentru a se potrivi cu cazul nostru specific.

arm-none-eabi-gcc -x assembler -c -O0 -mcpu = cortex-m4 -mthumb -Wall core. S -o core.o

Și asta a fost compilat.

Pasul 9: Conectarea programului

Direct din exemplul din articol, avem acest lucru:

arm-none-eabi-gcc core.o -mcpu = cortex-m0 -mthumb -Wall --specs = nosys.specs -nostdlib -lgcc -T./STM32F031K6T6.ld -o main.elf

Cele mai multe dintre cele de mai sus le-ați văzut. Mai jos este ceea ce este nou.

specs = nosys.specs

Acesta este un pic dificil de explicat.

Are legătură cu „semihosting” și „retargeting” și are legătură cu intrarea / ieșirea. De asemenea, are de-a face cu apeluri de sistem și biblioteci.

De obicei, sistemele încorporate nu oferă dispozitive standard de intrare / ieșire. Acest lucru ar afecta apelurile de sistem sau bibliotecă (exemplu: printf ()).

Semihosting înseamnă că depanatorul (vezi imaginea Pasului 11 cu porțiunea de depanare încercuită în roșu) are un canal special și folosește protocolul de semihosting și puteți vedea ieșirea printf () pe mașina gazdă (prin debugger).

Retargeting, pe de altă parte, înseamnă că aceleași apeluri de sistem sau bibliotecă înseamnă altceva. Ei fac altceva, care are sens pentru sistemul încorporat. Într-un sens, să spunem pentru printf (), există o nouă implementare, o implementare reorientată a acelei funcții.

După ce am spus toate acestea, --specs = nosys.specs înseamnă că nu vom fi semihosting. În mod normal, asta ar însemna că ne îndreptăm din nou. Asta ne aduce la următorul steag.

nostdlib

Opțiunea linker -nostdlib este utilizată pentru a lega un program destinat să ruleze independent. -nostdlib implică opțiunile individuale -nodefaultlibs și -nostartfiles. Mai jos discutăm cele două opțiuni separat, dar cea mai obișnuită utilizare este doar nostdlib pentru cumpărături one-stop. La conectarea unui program găzduit, bibliotecile de sistem standard, cum ar fi libc, sunt legate implicit, oferind programului acces la toate funcțiile standard (printf, strlen și prieteni). Opțiunea linker -nodefaultlibs dezactivează legătura cu acele biblioteci implicite; singurele biblioteci legate sunt exact acelea pe care le denumiți în mod explicit linkerului folosind steagul -l.

lgcc

libgcc.a este o bibliotecă standard care oferă subrutine interne pentru a depăși deficiențele anumitor mașini. De exemplu, procesorul ARM nu include o instrucțiune de divizare. Versiunea ARM a libgcc.a include o funcție de divizare, iar compilatorul emite apeluri către acea funcție acolo unde este necesar.

T

Acesta este doar un mod de a spune linkerului să folosească acest fișier ca script de linker. În cazul nostru, numele fișierului este linker.script.ld.

o main.elf

În cele din urmă, îi spunem linkerului care va fi numele fișierului de imagine final de ieșire care va fi ars / aruncat pe dispozitivul nostru.

Iată versiunea noastră a liniei de comandă complete, modificată pentru situația noastră specifică:

arm-none-eabi-gcc core.o -mcpu = cortex-m4 -mthumb -Wall --specs = nosys.specs -nostdlib -lgcc -T./linker.script.ld -o main.elf

Ne asigurăm că fișierul script și fișierul core.o sunt ambele în același director, unde vom rula linia de comandă de mai sus.

Și se leagă fără probleme.

O verificare

Apoi alergăm:

arm-none-eabi-nm main.elf

și obținem:

devchu @ chubox: ~ / Development / Atollic / TrueSTUDIO / STM32_workspace_9.1 $ arm-none-eabi-nm main.elf 20014000 A _stack 08000010 t main_loop 08000008 T reset_handler 08000000 T vtable

Arata bine. Comanda arm-none-eabi-nm este o modalitate de a lista simbolurile din fișierele obiect.

Pasul 10: Testarea conexiunii la STM32 Nucleo-64

Testare Conexiune la STM32 Nucleo-64
Testare Conexiune la STM32 Nucleo-64
Testare Conexiune la STM32 Nucleo-64
Testare Conexiune la STM32 Nucleo-64

Prima dvs. misiune, în cazul în care alegeți să o acceptați, este să vă determinați sistemul să vă vadă placa de dezvoltare.

Folosind Windows

Pentru Windows, am decis să instalez TrueSTUDIO de la Atollic (versiune gratuită). A fost o instalare nedureroasă și a instalat automat driverul, astfel încât să pot folosi st-link pentru a testa conexiunea. Odată ce am instalat TrueSTUDIO și managerul de dispozitive a văzut dispozitivul, am descărcat instrumentele texan / stlink sugerate de articolul Bare Metal pe care l-am urmărit. Am plasat din nou folderul direct sub „C: \” și am creat din nou câteva legături din coșul meu de acasă local cygwin către comenzi.

ln -s /c/STM32. MCU/stlink-1.3.0-win64/bin/st-info.exe ~ / bin / st-info

Ca test inițial pentru a vedea dacă putem comunica cu adevărat cu dispozitivul, am rulat:

st-info --probe

Și am revenit:

S-au găsit 1 programatori stlink

Deci, acum știm că putem vorbi / interoga consiliul nostru de dezvoltare.

Folosind Linux

Pentru Linux, nu aveți nevoie de driver. Dar pentru Debian, va trebui să construiți primele instrumente din sursă.

git clone

Asigurați-vă că aveți instalat libusb-1.0-0-dev.

lista apt | grep -E "* libusb. * dev *"

Ar trebui sa vezi:

libusb-1.0-0-dev / xenial, acum 2: 1.0.20-1 amd64 [instalat]

sau asa ceva.

Pentru a-l instala:

sudo apt-get install libusb-1.0-0-dev

Rețineți că cele de mai sus nu sunt la fel ca:

sudo apt-get install libusb-dev

Lipsa corectă a libusb dev poate provoca probleme cu cmake.

CMake Error: Următoarele variabile sunt utilizate în acest proiect, dar sunt setate la NOTFOUND. Vă rugăm să le setați sau să vă asigurați că sunt setate și testate corect în fișierele CMake: LIBUSB_INCLUDE_DIR (ADVANCED)

Treceți la directorul rădăcină al proiectului (… bla / bla / stlink). Faceți un „face eliberare”.

După acele versiuni, instrumentele ar trebui să fie sub „.. / build / Release”.

Apoi puteți rula „st-info --probe”. Iată ieșirea cu Nucleo conectat, apoi nu.

devchu @ chubox: ~ / Development / stlink $./build/Release/st-info --probe Găsit 1 programator stlink serial: 303636414646353034393535363537 openocd: "\ x30 / x36 / x36 / x41 / x46 / x46 / x35 / x30 / x34 / x39 / x35 / x35 / x36 / x35 / x37 "flash: 524288 (dimensiunea paginii: 2048) sram: 65536 chipid: 0x0446 descr: F303 dispozitiv de înaltă densitate devchu @ chubox: ~ / Development / stlink $./build/Release/st- info --probe S-au găsit 0 programatori stlink devchu @ chubox: ~ / Development / stlink $

Pasul 11: Să folosim GDB cu Linux

Să folosim GDB cu Linux
Să folosim GDB cu Linux
Să folosim GDB cu Linux
Să folosim GDB cu Linux

Dacă ați încercat toate acestea și ați ajuns până aici - minunat! Excelent. Hai să ne distrăm puțin acum.

Când cumpărați aceste plăci de dezvoltare ARM, indiferent dacă sunt MSP432 Launchpad de la Texas Instruments, sau cel despre care discutăm acum, Nucleo-F303 (STM32 Nucleo-64), acestea ajung de obicei deja fulgerate cu un program în execuție, de obicei un program intermitent care include, de asemenea, apăsarea unui comutator pentru a modifica rata cu care LED-ul (clipurile) intermitent (e).

Înainte de a ne grăbi atât de repede, să vedem ce trebuie să vedem și să facem.

Cu Linux, deschideți un terminal, schimbați directorul proiectului stlink git pe care tocmai l-am construit și găsiți instrumentul st-util.

devchu @ chubox: ~ / Development / stlink $ find. -nume st-util

./build/Release/src/gdbserver/st-util

Rulați acel instrument. Deoarece am testat deja conexiunea noastră cu st-info --probe, ar trebui să obținem o ieșire astfel:

devchu @ chubox: ~ / Development / stlink $./build/Release/src/gdbserver/st-util

st-util 1.4.0-50-g7fafee2 2018-10-20T18: 33: 23 INFO common.c: Se încarcă parametrii dispozitivului…. 2018-10-20T18: 33: 23 INFO comun.c: Dispozitivul conectat este: dispozitiv F303 de înaltă densitate, id 0x10036446 2018-10-20T18: 33: 23 INFO comun.c: dimensiune SRAM: 0x10000 octeți (64 KiB), Flash: 0x80000 octeți (512 KiB) în pagini de 2048 octeți 2018-10-20T18: 33: 23 INFO gdb-server.c: ID-ul cipului este 00000446, ID-ul de bază este 2ba01477. 2018-10-20T18: 33: 23 INFO gdb-server.c: Ascultare la *: 4242 …

Acesta este serverul GDB care rulează acum și vede placa noastră de dezvoltare și, mai important, ascultă pe portul 4242 (portul implicit).

Acum suntem gata să declanșăm clientul GDB.

În Linux, deschideți un alt terminal, introduceți acest lucru:

arm-none-eabi-gdb -tui

Este exact la fel ca rularea gdb strict pe linia de comandă, însă produce în schimb un terminal bazat pe text (presupun că folosește blesteme).

Avem clientul GDB și serverul GDB rulând. Cu toate acestea, clientul nu este conectat la server. În acest moment nu știe nimic despre Nucleo (sau tabloul la alegere). Trebuie să-i spunem. În terminal, solicitarea dvs. ar trebui să fie acum „(gdb)”. Introduce:

ajutor țintă

Vă va oferi o listă. Observați că cel pe care îl dorim este vizat extins-la distanță - Folosiți un computer la distanță prin intermediul unei linii seriale.

Dar trebuie să îi oferim și locația. Deci, la promptul (gdb), introduceți:

(gdb) țintă localhost extins-la distanță: 4242

Ar trebui să primiți înapoi un răspuns de genul:

(gdb) țintă localhost extins-la distanță: 4242

Depanare la distanță folosind localhost: 4242 0x080028e4 în ?? ()

Între timp, la terminalul care rulează st-util gdbserver, am obținut acest lucru:

2018-10-20T18: 42: 30 INFO gdb-server.c: S-au găsit 6 hw registre de puncte de întrerupere

2018-10-20T18: 42: 30 INFO gdb-server.c: GDB conectat.

Pasul 12: Să repetăm, cu Windows și Flash programul nostru

Să repetăm, cu Windows și Flash programul nostru
Să repetăm, cu Windows și Flash programul nostru
Să repetăm, cu Windows și Flash programul nostru
Să repetăm, cu Windows și Flash programul nostru
Să repetăm, cu Windows și Flash Programul nostru
Să repetăm, cu Windows și Flash Programul nostru

Pașii pentru rularea st-util gdbserver și clientul arm-none-eabi-gdb sunt în esență aceiași ca și în timpul pasului anterior. Deschideți două terminale (cygwin, DOS cmd sau Windows Powershell), găsiți locația st-util, rulați-l. În celălalt terminal, rulați clientul arm-none-eabi-gdb. Singura diferență este că modul -tui (vizualizarea textului bazat pe terminal) nu este cel mai probabil acceptat.

Dacă cele de mai sus au funcționat în Windows, atunci va trebui probabil să vă opriți (doar clientul). În acest moment, cumva va trebui să rulați clientul GDB unde se află fișierul dvs. de compilare („core.out”) sau să adăugați întreaga cale la acel fișier ca argument pentru clientul GDB.

Mi-am simplificat viața folosind cygwin și creând link-uri din directorul meu local $ HOME // bin către locul în care se află ambele instrumente.

Ok, am compilat și legat la fel ca înainte și avem fișierul main.elf gata pentru a fi intermitent.

Avem st-util care rulează într-o singură fereastră. Repornim clientul GDB, de data aceasta facem:

arm-none-eabi-gdb main.elf

Îl lăsăm să pornească, să așteptăm promptul (gdb), să facem aceeași comandă de conectare la serverul GDB (st-util) și suntem gata să intermitem executabilul. Este foarte anti-climatic:

(gdb) încărcare

Funcționând cu terminale cygwin, există o problemă cunoscută, când comenzile consolei nu se emit. Deci, în cazul nostru, fereastra care rulează serverul a fost complet tăcută. Cel care rulează clientul, unde am rulat încărcarea, a produs acest lucru:

Secțiunea de încărcare.text, dimensiune 0x1c lma 0x8000000 Adresa de pornire 0x8000000, dimensiunea de încărcare 28 Rată de transfer: 1 KB / sec, 28 octeți / scriere.

Pasul 13: intermitent cu Linux - Mai multe recompense: D

Intermitent cu Linux - Mai multe recompense: D
Intermitent cu Linux - Mai multe recompense: D

Pasul 14: Să scufundăm puțin mai adânc

Dacă ai ajuns aici, excelent. Să mergem mai departe.

De ce să nu vă uitați în fișierul main.elf, executabil? Rulați următoarele:

arm-none-eabi-objdump -d main.elf

Ar trebui să vedeți o ieșire de genul acesta:

main.elf: format de fișier elf32-littlearm

Demontarea secțiunii.text:

08000000:

8000000: 00 40 01 20 09 00 00 08.@. ….

08000008:

8000008: 4802 ldr r0, [buc, # 8]; (8000014) 800000a: 4685 mov sp, r0 800000c: 4f02 ldr r7, [pc, # 8]; (8000018) 800000e: 2000 mov r0, # 0

08000010:

8000010: 3001 adaugă r0, # 1 8000012: e7fd b.n 8000010 8000014: 20014000.word 0x20014000 8000018: deadbeef.word 0xdeadbeef

Ce pepite mici putem obține din rezultatul de mai sus?

Dacă vă amintiți când discutam și creăm fișierul linker.script.ld, am afirmat că aceste dispozitive ARM au RAM începând de la 0x20000000 și că memoria FLASH începe de la 0x08000000.

Astfel, putem vedea că într-adevăr programul este astfel încât totul rezidă în memoria FLASH.

Apoi, mai sus, dar un pas ulterior, când discutam porțiunea „Hello World”, a existat o declarație în care încărcăm o valoare imediată, constantă, literală („0xDEADBEEF”) într-un registru de bază MCU („R7”).

Declarația a fost:

LDR R7, = 0xDEADBEEF

În codul nostru, acesta este singurul loc în care menționăm chiar DEADBEEF. Nicaieri. Și totuși, dacă te uiți la instrucțiunile de mai sus demontate / reconstruite, etc, există mai multe despre DEADBEEF decât am crezut că am făcut.

Deci, compilatorul / linkerul a decis cumva să clipească permanent valoarea DEADBEEF într-o adresă FLASH, la locația 0x8000018. Și apoi, compilatorul a schimbat instrucțiunea LDR de mai sus pentru a fi:

LDR R7, [PC, # 8]

A generat chiar un comentariu pentru noi. Ce drăguț. Și ne spune să luăm valoarea curentă a contorului de program (registrul PC), să adăugăm 0x8 la acea valoare și acolo a fost ars DEADBEEF și să obținem acea valoare și să o umplem în R7.

Deci, asta înseamnă, de asemenea, că contorul de program (PC) arăta spre adresa 0x8000010, care este începutul main_loop și că valoarea DEADBEEF se află la două adrese după sfârșitul main_loop.

Pasul 15: În cele din urmă, o scurtă privire asupra programului care rulează

Chiar dacă părăsiți GDB, reintroduceți comanda. Nici măcar nu trebuie să-i dai niciun fișier; nu mai clipim, ci doar îl rulăm.

După ce ați reconectat clientul GDB la serverul GDB, la promptul de comandă (gdb):

(gdb) registre de informații

Ar trebui să vedeți așa ceva:

r0 0x0 0

r1 0x0 0 r2 0x0 0 r3 0x0 0 r4 0x0 0 r5 0x0 0 r6 0x0 0 r7 0x0 0 r8 0x0 0 r9 0x0 0 r10 0x0 0 r11 0x0 0 r12 0x0 0 sp 0x20014000 0x20014000 lr 0xffffffffff 42949672000

Dar apoi, la promptul (gdb), introduceți:

(gdb) continua

Și a lovit foarte repede CTRL-C. Aceasta ar trebui să întrerupă programul. Introduceți din nou comanda „registre de informații”.

De data aceasta, arată diferit:

(gdb) registre de informații

r0 0x350ffa 3477498 r1 0x0 0 r2 0x0 0 r3 0x0 0 r4 0x0 0 r5 0x0 0 r6 0x0 0 r7 0xdeadbeef 3735928559 r8 0x0 0 r9 0x0 0 r10 0x0 0 r11 0x0 0 r12 0x0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 16777216

Ce s-a întâmplat? Exact ceea ce ne-am dorit. DEADBEEF a fost încărcat în R7, iar R0 a crescut (extrem de rapid). Dacă repetați, veți vedea din nou R0 cu o altă valoare.

Pasul 16: Am vrut să creăm un tablou numai în citire în Flash

O modalitate de a crea echivalentul unui tablou folosind asamblare și directive, este următoarea:

.type myarray,% object // numele sau eticheta „myarray” este definită ca un tip de obiect.

myarray: // acesta este începutul declarației „myarray” // (în ce va consta)..word 0x11111111 // primul membru sau valoarea conținută în „myarray”..word 0x22222222 // a doua valoare (adrese contigue)..word 0x33333333 // și așa mai departe..size myarray,.-myarray // compilatorul / ansamblul știe acum unde este sfârșitul sau // limita „myarray”.

Acum, că l-am configurat în memoria FLASH, îl putem folosi în program. Mai jos este o porțiune:

LDR R1, myarray // acesta încarcă datele conținute la prima locație a „myarray”.” // nu asta vrem.

LDR R1, = myarray // aceasta încarcă valoarea locației în sine (prima adresă), // nu datele.. // Aceasta este ceea ce ne dorim.

MOV R2, # 0 // R2 va ține un număr pentru a ne asigura că nu mergem

// sfârșitul matricei. LDR R3, = myarrsize // R3 va fi echivalentul „myarrsize”.

// R0 ne va păstra datele

main_loop:

LDR R0, [R1] // Încărcați datele arătate de R1 („myarray”) în R0. CMP R2, R3 // Suntem la limita matricei? BEQ main_loop // Dacă am terminat, am terminat, așa că ne vom bucura pentru totdeauna.

ADAUGĂ R2, # 1 // În caz contrar, putem continua să iterăm prin matrice.

ADĂUGAȚI R1, # 4 // Adăugați 4 pentru a înregistra R1, astfel încât să indice corect spre următorul

// abordare..

B main_loop // Bucla înapoi.

Videoclipul trece prin toate acestea și există un bug în el. Este bine; arată că este important să ruleze și să depaneze codul. Arată un caz clasic de mers pe jos de la capătul unei matrice.

Recomandat: