Keďže vývojové prostriedky máme nainštalované, môžme začať s prvým programom. Na veľmi jednoduchom príklade si ukážeme, ako pripraviť projeky v C a dve varianty projektov v assembleri
Na nasledujúcom jednoduchom programe si ukážeme, ako pripraviť projekt pre nástroje GNU. Ukážeme si projekt v C a takisto dve varianty projektu v assembleri. Projekty využívajú utilitu make. Pokiaľ make nepoznáte, skúste si pozrieť článok MAKE tajomstva zbavený.
Všetky uvedené projekty sú kompletné a funkčné. Môžete ich použiť ako základ pre vlastné projekty. Projekty si môžete stiahnuť z prílohy tohoto článku.
Ukážkový program je jednoduchý:
- vypne watchdog
- nastaví hodiny na DCO a nastaví čo najvyššiu frekvenciu
- v nekonečnej slučke bude meniť hodnotu výstupného pinu P1.0
Najprv program v C. Samotný program je jasný a nevyžaduje žiaden komentár.
Hlavičkový súbor io.h, uvedený na začiatku, obsahuje definície všetkých portov, špeciálnych registrov a hodnôt jednotlivých bitov.
#include <io.h>
int q=0;
main()
{
long i;
WDTCTL=WDTPW+WDTHOLD;
DCOCTL=DCO0 | DCO1;
BCSCTL1=RSEL0 | RSEL1 | RSEL2;
BCSCTL2=SELM0;
P1DIR=0x01;
P1SEL=0x00;
while (1) {
P1OUT=q & 1;
for (i=0;i<0x50000l;i++);
q++;
}
}
A tu je k nemu príslušný Makefile:
MCU=msp430x1132
TARGET=test1
OBJECTS=test1.o
CFLAGS=-g -mmcu=$(MCU)
LDFLAGS=-g -mmcu=$(MCU)
CC=msp430-gcc
all: $(TARGET)
$(TARGET): $(OBJECTS)
$(CC) $(LDFLAGS) -o $@ $?
%.o : %.c
$(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $<
clean:
rm -f $(TARGET) $(OBJECTS)
Pozrime sa na význam použitých prepínačov:
- -g chceme, aby program obsahoval ladiacie informácie
- -o stanovuje názov výstupného súboru
- -c špecifikuje, že zdrojový kód chceme iba skompilovať
- -mmcu určuje typ MCU
Pri kompilácii nepoužívame žiadnu optimalizáciu. V prípade, že by sme optimalizáciu zapli, čakacia slučka by bola zoptimalizovaná (prípadne úplne odstránená) a program by prestal fungovať podľa našich predstáv.
Pozrime sa teraz na ten istý program prepísaný do assembleru. Najprv si všimnime direktívu #include – táto direktíva nám naznačuje, že musíme použiť C-čkový preprocesor. Tým získame možnosť využiť všetky deklarácie portov, špeciálnych registrov a ich bitových hodnôt, ktoré máme k dispozícii v C. Preto budeme v našich príkladoch uvažovať aj s použitím preprocesora.
.nolist
#include <io.h>
.list
.text
start:
mov #WDTPW+WDTHOLD, &WDTCTL
mov #0x300,R1
mov.b #(DCO0 | DCO1 | DCO2),&DCOCTL
mov.b #(RSEL0 | RSEL1 | RSEL2),&BCSCTL1
mov.b #SELM0,&BCSCTL2
mov.b #0x00,&P1SEL
bis.b #BIT0,&P1DIR
clr r5
clr r6
mov #6,r7
onoff:
mov.b r5,&P1OUT
again:
inc r6
jnc again
dec r7
jnz again
mov #6,r7
add #1,r5
jmp onoff
noint:
reti
.section ".vectors", "ax"
InterruptVectors:
.rept 15
.word noint
.endr
.word start
.end
Teraz sa pozrime na prvú variantu Makefile. V tejto variante využijeme kompilátor C aby nám vytvoril priamo objektový súbor. Aby kompilátor C spracoval zdrojový text v assembleri, potrebujeme použiť špeciálne prepínače.
MCU=msp430x1132
TARGET=test1
OBJECTS=test1.o
CPPASFLAGS= -Wa,-gstabs -D_GNU_ASSEMBLER_ -x assembler-with-cpp
CPPASFLAGS += -Wa,-als -Wa,-a=${@:.o=.lst}
CPPFLAGS= -mmcu=$(MCU)
LDFLAGS= -g -m $(MCU) --cref -Map $@.map
CC=msp430-gcc
LD=msp430-ld
all: $(TARGET)
$(TARGET): $(OBJECTS)
$(LD) $(LDFLAGS) -o $@ $?
%.o : %.S
$(CC) $(CPPASFLAGS) $(CPPFLAGS) -c -o $@ $<
clean:
rm -f $(TARGET) $(TARGET).map $(TARGET).lst $(OBJECTS)
Prepínače pre kompilátor:
- -x assembler-with-cpp – určuje, že po spracovaní preprocesorom sa na ďalšiu kompiláciu použije assembler
- -D_GNU_ASSEMBLER_ – definícia symbolu, ktorý oznámi hlavičkovým súborom, že sú použité v zdrojovom texte assemblera
- -mmcu určuje typ MCU
- -Wa,-gstabs – parameter -gstabs sa prenesie do assemblera (-Wa je prepínač určený na tento účel); tento prepínač určuje, že vo výstupnom súbore chceme mať ladiace informácie (-g) v špecifikovanom formáte (stabs)
- -Wa,-als – opäť parameter pre assembler, určujúci formát listingu
- -Wa,-a=${@:.o=.lst} – definovanie názvu súboru s listingom; názov súboru je odvodený od názvu zdrojového súboru
- -c – iba kompilácia (vytvorenie objektového súboru)
- -o – určenie názvu výstupného súboru
Prepínače pre linker:
- -g – vo finálnom programe chceme ladiace informácie
- -m $(MCU) – určenie typu MCU
- –cref – pridá do mapy krížové referencie
- -Map $@.map – určenie názvu súboru, do ktorého sa zapíše mapa; názov súboru je odvodený od mena programu
- -o – určenie názvu výstupného súboru
Pri kompilácii sme assembleru určili formát ladiacich informácií – stabs. Pokiaľ ho nezadáme, ladiace informácie sa vygenerujú vo formáte dwarf2 – bohužiaľ, s týmto formátom má debugger (gdb) problémy. Pri C-čkovom projekte sme sa o formát ladiacich informácií nemuseli starať, pretože kompilátor C používa stabs formát automaticky.
Iná varianta projektu pre assembler využíva z kompilátora C iba preprocesor a na kompiláciu predspracovaného súboru volá priamo assembler.
MCU=msp430x1132
TARGET=test1
OBJECTS=test1.o
CPPFLAGS=-D_GNU_ASSEMBLER_ -mmcu=$(MCU)
ASFLAGS=-gstabs -als -a=${@:.o=.lst} -mmcu=$(MCU)
LDFLAGS= -g -m $(MCU) --cref -Map $@.map
CC=msp430-gcc
LD=msp430-ld
AS=msp430-as
all: $(TARGET)
$(TARGET): $(OBJECTS)
$(LD) $(LDFLAGS) -o $@ $?
%.o : %.S
%.o : %.s
$(AS) $(ASFLAGS) -o $@ $<
%.s : %.S
$(CC) $(CFLAGS) $(CPPFLAGS) -E -o $@ $<
clean:
rm -f $(TARGET) $(TARGET).map $(TARGET).lst $(OBJECTS) test1.s
Čo sa týka prepínačovm jediná zmena je chýbajúci prepínač „-x assembler-with-cpp“ a prepínač -c bol nahradený prepínačom -E – tento prepínač znamená, že GCC spustí iba preprocesor, bez akejkoľvek ďalšej kompilácie.
Takže už nám ostáva program nahrať do pamäte procesora a spustiť ho. Ale o tom nabudúce.
Vzorové projekty si mlžete stiahnuť tu.