====== Biblioteka CMSIS pod GCC ======
//Artykuł z serii „Zanim zapomnę to napiszę cokolwiek”, więc proszę o rozbudowanie w miarę możliwości kolejnych podążających według „poradnika”.//
Uwaga: w przykładach używam nazw archiwów, plików specyficznych dla serii [[http://www.st.com/web/catalog/mmc/FM141/SC1169/SS1031/LN1565/PF189782|STM32F103CB]] mikrokontrolerów STM32, ale postępowanie dla innych powinno być z grubsza analogiczne.
- Wyszukujemy na stronach ST archiwum, które po rozpakowaniu da nam katalog o nazwie: **STM32F10x_StdPeriph_Lib_V3.5.0**
- Tworzymy katalog roboczy - powiedzmy //~/stm32/szablon//, w którym tworzymy trzy podkatalogi: //src//, //inc// i //misc//
- Katalog //src// będzie zawierał właściwe definicje funkcji tj. pliki .c i , zaś katalog //inc// będzie zawierał pliki nagłówkowe. Katalog //misc// będzie miejscem (póki co) na skrypt linkera.
- Szukamy w czeluściach archiwum od ST następujących plików:
- core_cm3.c i core_cm3.h (Libraries/CMSIS/CM3/CoreSupport)
- stm32f10x.h (Libraries/CMSIS/CM3/DeviceSupport/ST/STM32F10x)
- system_stm32f10x.c i system_stm32f10x.h (Libraries/CMSIS/CM3/DeviceSupport/ST/STM32F10x)
- startup_stm32f10x_md.s (Libraries/CMSIS/CM3/DeviceSupport/ST/STM32F10x/startup/TrueSTUDIO)
- Znalezione pliki .c kopiujemy oczywiście do //src// zaś .h do //inc//. W pliku .s zmieniamy na .S (duża literka) i również umieszczamy w //src//.
- Szukamy pliku stm32_flash.ld (Project/STM32F10x_StdPeriph_Template/TrueSTUDIO/STM3210B-EVAL) i kopiujemy do //misc//.
- Szukamy pliku stm32f10x_conf.h (Project/STM32F10x_StdPeriph_Template) i kopiujemy do głównego katalogu szablonu (//~/stm32/szablon///).
- Opcjonalnie dodajemy do odpowiednich katalogów pliki z Libraries/STM32F10x_StdPeriph_Driver.
- Pobieramy aktualne Makefile z [[https://gist.github.com/pidpawel/9165345|gist'a]] albo z mirrora: <code makefile>TARGET=main
ADDITIONAL=
LIBS=src/startup_stm32f10x_md.o src/core_cm3.o src/system_stm32f10x.o
PERIPH=src/stm32f10x_adc.o src/stm32f10x_bkp.o src/stm32f10x_can.o src/stm32f10x_cec.o src/stm32f10x_crc.o src/stm32f10x_dac.o src/stm32f10x_dbgmcu.o src/stm32f10x_dma.o src/stm32f10x_exti.o src/stm32f10x_flash.o src/stm32f10x_fsmc.o src/stm32f10x_gpio.o src/stm32f10x_i2c.o src/stm32f10x_iwdg.o src/stm32f10x_pwr.o src/stm32f10x_rcc.o src/stm32f10x_rtc.o src/stm32f10x_sdio.o src/stm32f10x_spi.o src/stm32f10x_tim.o src/stm32f10x_usart.o src/stm32f10x_wwdg.o
OBJS=$(LIBS) $(PERIPH) $(ADDITIONAL) src/$(TARGET).o
LD_SCRIPT=misc/stm32_flash.ld
INCPATH=inc/
OPTIMIZE = O2
TARGET_CPU=cortex-m3
CFLAGS = -$(OPTIMIZE)
# CFLAGS += -g2
CFLAGS += -Wall
CFLAGS += -Wno-unused-result
CFLAGS += -Wno-write-strings
#CFLAGS += -Wnoimplicit-function-declaration
CFLAGS += -std=gnu99
CFLAGS += -mthumb -mcpu=$(TARGET_CPU)
CFLAGS += -fno-builtin-printf -Wno-main
CFLAGS += -I$(INCPATH)
CFLAGS += -DSTM32F10X_MD
CFLAGS += -DUSE_STDPERIPH_DRIVER
CFLAGS += -I`pwd`
# mozliwosc optymalizacji kodu w czasie linkowania
# to jest genialne, ale wymaga czasami modyfikacji kodu :P
#
# - *_Handler also need to be modificatory by "_attribute__((used))".
# - Lopatologicznie: Funkcje o ktore sie drze na koncu ze ich nie ma
# musza byc oznaczone jako uzywane (zeby ich nie wywalal)
# CFLAGS += -flto
LDFLAGS = $(CFLAGS)
LDFLAGS += -nodefaultlibs
LDFLAGS += -nostartfiles
# usuwanie nieuzywanych
LDFLAGS += -Wl,--gc-sections
CFLAGS += -fdata-sections -ffunction-sections
TOOLCHAIN_PREFIX=arm-none-eabi-
CC=$(TOOLCHAIN_PREFIX)gcc
LD=$(TOOLCHAIN_PREFIX)gcc
OBJCOPY=$(TOOLCHAIN_PREFIX)objcopy
OBJDUMP=$(TOOLCHAIN_PREFIX)objdump
SIZE=$(TOOLCHAIN_PREFIX)size
all: $(TARGET).elf $(TARGET).bin $(TARGET).hex listing stats
%.o: %.c
$(CC) $(CFLAGS) -c $< -o $@
%.o: %.s
$(CC) $(CFLAGS) -c $< -o $@
$(TARGET).elf: $(OBJS) $(STARTUP)
$(LD) $(LDFLAGS) -T$(LD_SCRIPT) $^ -o $@
%.hex: %.elf
$(OBJCOPY) -O ihex $< $@
%.bin: %.elf
$(OBJCOPY) -O binary $< $@
stats: $(TARGET).elf
$(SIZE) --format=berkeley $(TARGET).elf
listing: $(TARGET).elf
$(OBJDUMP) -h -S $(TARGET).elf > $(TARGET).lst
dump: $(TARGET).elf
$(OBJDUMP) -d -S $<
dump_all: $(TARGET).elf
$(OBJDUMP) -D $<
debugserver:
openocd -f /usr/share/openocd/scripts/interface/stlink-v2.cfg -f /usr/share/openocd/scripts/target/stm32f1x_stlink.cfg
debug: $(TARGET).elf
(echo "target remote localhost:3333"; cat) | arm-none-eabi-gdb $(TARGET).elf
clean:
rm -f $(OBJS) $(STARTUP) $(TARGET).elf $(TARGET).hex $(TARGET).bin $(TARGET).lst
</code>
- Tworzymy plik main.c z szablonem: <code c>#include <stdint.h>
#include "stm32f10x.h"
volatile uint32_t msTicks = 0;
void SysTick_Handler(void) {
msTicks++;
}
void delay_ms(uint32_t ms) {
uint32_t now = msTicks;
while ((msTicks-now) < ms){}
}
int main(void) {
SysTick_Config(SystemCoreClock/1000);
RCC->APB2ENR |= RCC_APB2ENR_IOPBEN;
GPIOB->CRL = 0x1111;
while (1) {
GPIOB->ODR |= 0xFFFF;
delay_ms(100);
GPIOB->ODR &= ~0xFFFF;
delay_ms(100);
}
}
</code>
I… właściwie mamy gotowe środowisko. Polecam dostosować plik _conf.h do swojej konkretnej aplikacji, jak również plik Makefile. Może się okazać również, że potrzeba delikatnie zmodyfikować pliki dostarczone przez ST (skrypt startowy zawiera odwołanie do //<nowiki>__</nowiki>libc_init_array// (osobiście wykomentowałem), funkcje uint32_t <nowiki>__</nowiki>STREXB(uint8_t value, uint8_t *addr), uint32_t <nowiki>__</nowiki>STREXH(uint16_t value, uint16_t *addr), uint32_t <nowiki>__</nowiki>STREXW(uint32_t value, uint32_t *addr) zawierają kod asemblera z niepoprawną (przynajmniej dla GCC składnią) - należy wyedytować zgodnie z sugestią na dole [[http://www.freddiechopin.info/pl/artykuly/35-arm/79-przykady-dla-stm32-stm32f10x-standard-peripherals-library?start=4|z tego artykułu]] i prawdopodobnie jeszcze kilka mniejszych problemów o których zdążyłem zapomnieć/rozwiązać w Makefile).
Przypominam, że znaki handlowe takie jak ARM, CMSIS, ST, STM i STM32 należą do odpowiednich instytucji i używam ich jedynie w celach edukacyjnych.
Życzę miłej zabawy tymi mocarnymi klockami, zapraszam do rozwijania tego poradnika, jak również zapełniania całego namespace [[poradniki:stm32:start|/poradniki/stm32]] ;)