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.