Formål
Formålet med denne øvelse er at erfare
hvordan U-Boot er et vigtigt værktøj til debugging af hardware i en typisk
embedded Linux platform. Du vil opleve hvordan du med med U-Boot har direkte
adgang til processorens rå ressourcer og kan tilgå disse. Dette er i modsætning
til senere når vi benytter Linux og den abstraktion som operativ systemet giver
over hardwaren.
Du skal have et funktionelt VM-Ware Image,
et Devkit8000 og et USB-serial konverter kabel (med mindre din PC er så gammel
at den har en RS-232 port direkte)
U-Boot er udover at være en platform for
booting af et operativsystem også et godt værktøj til den første debugging af
hardware. Som du vil se i øvelsen kan vi tilgå processorens enheder direkte og
afvikle simple testprogrammer direkte fra U-Boot.
Som vi gennemgik i lektionen omkring
busser, så har vi i OMAP processoren et stort memory map, indeholdende en masse
forskellige enheder og konfigurations registre til disse. Da enhederne er
mappet direkte i memory kan disse tilgås direkte på deres fysiske adresse vha
U-Boot.
I OMAP3530’s reference manual, kapitel 25,
finder vi sektionen omkring GPIO. GPIO (General Purpose Input/Output), er
simple pins på processoren som kan konfigureres til hhv in- og output. Hvis pin’en
er sat til output, kan vi tilskrive den en værdi og omvendt læse fra den, hvis
den er sat op til input.
Til styring af dette har OMAP’en 3 vigtige
registre:
§
GPIO_OE – Styring
af pin direction (in/out)
§ GPIO_DATAIN – Værdi læst
fra pin (’1’ / ’0’)
§ GPIO_DATAOUT – Værdi som
skal sættes på pin
Du kan finde mere om disse register i
1.6.2.9-1.6.2.11 i OMAP3530 ref manualen kapitel 25.
Nogle af OMAP’ens GPIO pins er forbundet
direkte til lysdioder og knapper på devkit8000.
Det er disse som vi skal lege lidt med i
denne øvelse.
Der er 192 GPIO’er på OMAP kredsen. Disse
er internt grupperet i 6 forskellige banke af 32-bit hver. Hver GPIO pin på en
bank kan således beskrives vha en bit i bankens tilhørende registre. Den
følgende figure er taget fra manualen og illustrerer hvordan at de forskellige
GPIO porte er mappet ind på de forskellige banke.
Som det ses af figuren føres GPIO[31:0] ind på GPIO bank 1. Skal vi arbejde med GPIO3 skal vi arbejde på bit 3 i bank 1.
Hvis man gerne vil læse / skrive til
memory i U-Boot, kan man benytte kommandoerne:
md.<address>
<no elements to read>
mw.<b/w/l>
<address> <value>
Benyt OMAP ref manualen til at finde
beskrivelsen af de 3 førnævnte registre. Brug herefter md til at udlæse værdien
af de enkelte registre samt mw til at sætte en ønsket værdi. Husk at b = 8-bit,
w=16-bit og l=32-bit. Husk at bevare værdierne af de bits som du ikke skal
ændre på. Ændrer du på disse, ændrer du på porte som har forbindelser til andre
enheder på DevKittet. Dette gøres ved først at læse værdien af registret, og
bagefter skrive værdien tilbage incl de ændringer som du har.
a) Benyt Devkit8000 schematic (findes på
devkit8000 wiki’en) til at finde ud hvilke IOs som følgende er forbundet til?
§ USER_KEY
- GPIO_26
- OE is located at 0x48310034
- Is located at 0x48310038
§ SYS_LED3
- GPIO163
- OE is located at 0x49058034
- Is located at 0x4905803c
b) I user manualen (spruf98c) skal du i
afsnittet om ”General Purpose I/O Interface”, CH 24 (spuf98v), finde ud af
hvilke GPIO banke (1-6) er førnævnte I/Os forbundet til (brug figur 24-4
(spuf98v)):
§ USER_KEY
- GPIO1
module
§ SYS_LED3
- GPIO6
module
Når du er nået så langt, ved du hvilken
GPIO bank som de forskellige lysdioder er forbundet til. Dette skal du bruge i
det følgende hvor du skal tilgå disses data registre direkte. \\ Se afsnittet "General-Purpose
Interface Register Manual" i kapitlet, her vil du se en oversigt over alle
gpio registrene, vi vil fokusere på de tidligere nævnte ”GPIO_OE”,
”GPIO_DATAIN” og ”GPIO_DATAOUT”. Så fortsæt om til beskrivelsen af disse på de
følgende sider. Bemærk hvorledes at der er angivet adresser for de respektive
GPIO banke. Dvs. læser du noget læser du noget fra adresse 0x49050000 har du
fat i GPIO bank 2, dvs. gpio [63:32], hvor bit 0 afspejler GPIO 32 osv.
c) Verificer om GPIO_OE værdien for hhv. USER_KEY
(input) og SYS_LED3 (output) er korrekte og korriger i fald at det ikke er
tilfældet (Benyt md.l [address] [length] og mw).
Dvs. alle pins i bank 1 er inputs, hvilket er godt nok!
Dvs. alle bits er inputs.
Læser inputregisteret for GPIO6, hvor SYS_LED3 sidder
d) Læs GPIO_DIN værdien for USER_KEY’s
GPIO bank og verificer om en bit skifter værdi når knappen er trykket ned eller
ej.
Bemærk Little endian
e) Skriv til GPIO_DOUT værdien for
SYS_LED3 og verificér at lysdioden tænder/slukker.
Øvelse 2: Skriv et program til at aktivere
lysdioderne
Du/I skal nu skrive et C-program som kan
udlæse status af USER_KEY og benytte denne til at tænde og slukke for lysdioden
SYS_LED3.
Tag udgangspunkt i hello_world.c som
findes under /user/stud/source/u-boot/standalone/examples.
a) U-Boot skal kompileres
før en vi kan lave vore prog
b) ram: i
/home/stud/source/u-boot/ skriver du/I:
$ make
CROSS_COMPILE=arm-angstrom-linux-gnueabi- distclean
$ make
CROSS_COMPILE=arm-angstrom-linux-gnueabi- devkit8000_config
$ make
CROSS_COMPILE=arm-angstrom-linux-gnueabi-
Alle registre er direkte memory mappede,
det vil sige at vi kan tilgå deres fysiske adresse direkte. Skal vi gøre dette
direkte i et c-program, skal vi huske tilbage på pointere.
volatile unsigned long *GpioOE_ptr = 0xdeadbeef; // Oprettelse af pointer til
//
fysisk adresse 0xdeadbeef
unsigned long gpioOE; // Oprettelse
af variabel til
// at holde værdi
gpioOE = *GpioOE_ptr; // Læsning af
værdi fra
// fysisk adresse.
*gpioOE_ptr = gpioOE; // Skrivning
til fysisk adresse
b) Benyt en simpel teksteditor (ex kate)
til at ændre hello_world.c til at kunne udlæse status af USER_BUTTON og i en
efterfølgende iteration benytte værdien af denne til at sætte værdien af
SYS_LED3
c) Kompilér programmet. (Du/I skal du/I
stå i u-boot folderen og skrive):
/home/stud/source/u-boot/$
make CROSS_COMPILE=arm-angstrom-linux-gnueabi-
Filerne beskrevet i Makefile’en under
./standalone/examples bliver herved bygget med variabler fra u-boot’s make
scripts.
d) Overfør programmet til U-Boot på
target. Vi benytter Y-Modem protokollen og der den ikke installeret i Ubunto,
skriver du/I:
$ sudo apt-get install lrzsz
Vi skal bruge en usb-serial port konverter
(samt et null-modem kabel) for at forbinde til devkittet. Du/I skal forbinde
null-modem kablet til serial port 0 som er den der sidder umiddelbart under
power-afbryderen. USB-serial konverteren plugges i din PC og forbindes in i
VMWare. Ved Ubunto prompten kan du/I checke om den er forbundet ind i Linux:
$ ls /dev/ttyU*
Der skulle gerne ligge en fil som hedder
ttyUSB0 i device folderen. Vi kommer nærmere ind på hvad det betyder i en
senere lektion. Nu skal vi have fat i target, så vi starter en seriel terminal
i vores Ubunto miljø, vi benytter i dette tilfælde minicom:
$ sudo apt-get
install minicom
$ minicom
Bemærk at minicom har en default terminal
og at denne terminal ikke nødvendigvis er det samme som den du/I ønsker. Læs
derfor man siderne og find ud af hvilken option der skal bruges for at vælge en
specifik terminal.
Når I har startet minicom op, så verificer den serielle opsætning. Den skal gerne ser ud som følgende:
Hardware Flow Control: No
Software Flow
Control: No
115200 8N1.
Start Devkit8000 og tryk en taste for at
afbryde boot. Ved U-Boot propmten taster du/I:
OMAP3 DevKit8000 # loady 0x80300000
Bemærk at vi loader et program til den
adresse i memory, som vi kompilerede programmet til.
Tast ctrl-a og derefter ’z’ for at åbne
menu’en i minicom. Tast her ’s’ for ”send”, vælg ”Ymodem” og vælg filen i det
rette bibliotek. PgUp / PgDown virker og tryk to gange på mellemrumstasten for
at hoppe ind i et bibl. Under /home/stud/source/u-boot/examples/standalone vælges
hello_world.bin med mellemrumstasten og sender vha ’enter’.
Når filen er loaded, startes programmet
med:
OMAP3 DevKit8000 # go 0x80300000
Eventuelle argumenter skrives efter
adressen, præcis som når vi kalder et program i dos/linux.
Nu skulle du/I gerne kunne styre lysdioden
præcis som fra prompten.
Hvis duII ikke får jeres funktioner
udført, kan det være fordi du/I har tilføjet flere hvilket kan få den konsekvens
at main funktionen hello_world() ikke længere ligger præcist på 0x80300000.
Ved skrive:
$ arm-angstrom-linux-gnueabi-nm -n
examples/standalone/hello_world
får du/I noget som ligner det her:
80300000 T
ledEnable
8030002c T
ledToggle
80300058 T
hello_world
80300100 T dummy
... snip ...
Her kan det tydelig ses at hello_world()
funktionen ikke længere ligger på 0x80300000, men det gør funktionen
ledEnable() derimod. Så faktisk er det kun denne der vil blive udført hvis der
skrives go 0x80300000.
Derfor for at få hello_world() funktionen
udført skal du/I skrive:
OMAP3 DevKit8000 # go 0x80300058
Ingen kommentarer:
Send en kommentar