STM32 в Linux
В данном посте я опишу процесс развертывания минимальной сборки для того чтобы собрать проект и прошить микроконтроллер с помощью программатора st-link, на примере отладочной платы STM32L-Discovery.
Самое главное для любой разработки под другие архитектуры, это toolchain. Мной был выбран Sourcery G++ Lite. Он доступен с официального сайта. На момент написания поста, была доступна последняя версия 2011.03-42.
Качается Toolchain в виде архива. Поэтому разархивированием его запихнем /opt. На моем примере у меня получилось так: /opt/codesourcery/arm-2011.03/. А внутри уже файлы из архива.
Далее нам потребуется отладчик и собственно тот инструмент с помощью которого мы сможем прошить микроконтроллер: OpenOCD. Этот инструмент так же можно скачать бесплатно с sourceforge.net.
Процесс установки описан в архиве с OpenOCD, но для ленивых приведу пример процесса установки:
tar -zxvf openocd-x.x.x.tar.gz
cd openocd-x.x.x.tar.gz
./configure --prefix=/usr --enable-jlink --enable-amtjtagaccel --enable-ft2 --enable-stlink
make
sudo checkinstall make install
Следующим шагом для нас будет скачать библиотеки для необходимого нам контроллера. Их можно скачать на сайте st.com. В нашем случае это STM32L1xx standard peripherals library. Этот архив содержит множество различных библиотек и много других важных для сборки инструментов.
Распакуем содержимое архива, и покидаем в папку с проектами папки Utilities и Libraries. Первая папка содержит различные библиотеки связанные с отладочной платой, а именно STM32L-Discovery. А вторая, все остальное необходимое. Теперь важно выбрать линковщик и sturtup файл для нашей сборки. Линковщик можно найти в директории Projects, в папке с Templates. Для своего проекта, я выбрал линковщик для TrueSTUDIO, поэтому вытащим STM32_flash.ld соответствующего микроконтроллера в предварительно созданную папку Linker в папке с проектами.
Когда все приготовления закончены, нам нужно как то собрать проект. Для этого создадим папку проекта, если конечно у вас ее еще нет. Примеры проектов можно взять все из того же архива от st.com. И так, когда проект был выбран и помещен в папку с проектами, создадим файлик, который поможет нам в сборке прошивки для микроконтроллера: Makefile.
Я не буду объяснять все тонкости его создания, т.к. об этом можно найти множество информации в интернете, поэтому приведу свой вариант боевого, так сказать, файлика Makefile:
####################################################
#
# On command line:
#
# make all = Create project
#
# make clean = Clean project files.
#
# To rebuild project do "make clean" and "make all".
#
#################################################
#
# Start of default section
#
#TOOLCHAIN = /opt/gcc-arm-none-eabi/bin
TOOLCHAIN = /opt/codesourcery/arm-2011.03/bin
TRGT = $(TOOLCHAIN)/arm-none-eabi-
CC = $(TRGT)gcc
LD = $(TRGT)gcc
CP = $(TRGT)objcopy
AS = $(TRGT)as#gcc -x assembler-with-cpp
AR = $(TRGT)ar
GDB = $(TRGT)gdb
HEX = $(CP) -O ihex
BIN = $(CP) -O binary -S
MCU = cortex-m3
# List all default C defines here, like -D_DEBUG=1
DDEFS = -DSTM32L1XX_MD -DUSE_STDPERIPH_DRIVER
# List all default ASM defines here, like -D_DEBUG=1
DADEFS =
# List all default directories to look for include files here
DINCDIR =
# List the default directory to look for the libraries here
DLIBDIR =
# List all default libraries here
DLIBS =
#
# End of default section
#################################################
#################################################
# Start of user section
#
#
# Define project name and Ram/Flash mode here
PROJECT = IOToggle
RUN_FROM_FLASH = 1
# List all user C define here, like -D_DEBUG=1
UDEFS =
# Define ASM defines here
UADEFS =
# List C source files here
LIBSDIR = ../Libraries
CORELIBDIR = $(LIBSDIR)/CMSIS/Include
DEVDIR = $(LIBSDIR)/CMSIS/Device/ST/STM32L1xx
DEVINCDIR = $(DEVDIR)/Include
STMSPDDIR = $(LIBSDIR)/STM32L1xx_StdPeriph_Driver
STMSPSRCDDIR = $(STMSPDDIR)/src
STMSPINCDDIR = $(STMSPDDIR)/inc
#STMUSBDIR = $(LIBSDIR)/STM32_USB-FS-Device_Driver
#STMUSBSRCDIR = $(STMUSBDIR)/src
#STMUSBINCDIR = $(STMUSBDIR)/inc
DISCOVERY = ../Utilities/STM32_EVAL/STM32L152D_EVAL
LINKER = ../Linker
LDFILE = STM32_flash.ld
SRC = ./main.c
SRC += ./system_stm32l1xx.c
SRC += ./stm32l1xx_it.c
#SRC += $(DEVDIR)\Source\Templates\system_stm32f0xx.c
#SRC += startup_stm32f0xx.S
#SRC += $(DISCOVERY)\stm32f0_discover
#y.c
## used parts of the STM-Library
SRC += $(STMSPSRCDDIR)/misc.c
SRC += $(STMSPSRCDDIR)/stm32l1xx_exti.c
SRC += $(STMSPSRCDDIR)/stm32l1xx_pwr.c
SRC += $(STMSPSRCDDIR)/stm32l1xx_adc.c
SRC += $(STMSPSRCDDIR)/stm32l1xx_flash.c
SRC += $(STMSPSRCDDIR)/stm32l1xx_rcc.c
SRC += $(STMSPSRCDDIR)/stm32l1xx_aes.c
SRC += $(STMSPSRCDDIR)/stm32l1xx_flash_ramfunc.c
SRC += $(STMSPSRCDDIR)/stm32l1xx_rtc.c
SRC += $(STMSPSRCDDIR)/stm32l1xx_aes_util.c
SRC += $(STMSPSRCDDIR)/stm32l1xx_fsmc.c
SRC += $(STMSPSRCDDIR)/stm32l1xx_sdio.c
SRC += $(STMSPSRCDDIR)/stm32l1xx_comp.c
SRC += $(STMSPSRCDDIR)/stm32l1xx_spi.c
SRC += $(STMSPSRCDDIR)/stm32l1xx_crc.c
SRC += $(STMSPSRCDDIR)/stm32l1xx_i2c.c
SRC += $(STMSPSRCDDIR)/stm32l1xx_syscfg.c
SRC += $(STMSPSRCDDIR)/stm32l1xx_dac.c
SRC += $(STMSPSRCDDIR)/stm32l1xx_iwdg.c
SRC += $(STMSPSRCDDIR)/stm32l1xx_tim.c
SRC += $(STMSPSRCDDIR)/stm32l1xx_dbgmcu.c
SRC += $(STMSPSRCDDIR)/stm32l1xx_lcd.c
SRC += $(STMSPSRCDDIR)/stm32l1xx_gpio.c
SRC += $(STMSPSRCDDIR)/stm32l1xx_usart.c
SRC += $(STMSPSRCDDIR)/stm32l1xx_dma.c
SRC += $(STMSPSRCDDIR)/stm32l1xx_opamp.c
SRC += $(STMSPSRCDDIR)/stm32l1xx_wwdg.c
## used parts of the USB Device Driver STM-Library
#SRC += $(STMUSBDIR)/usb_core.c
#SRC += $(STMUSBDIR)/usb_init.c
#SRC += $(STMUSBDIR)/usb_int.c
#SRC += $(STMUSBDIR)/usb_mem.c
#SRC += $(STMUSBDIR)/usb_regs.c
#SRC += $(STMUSBDIR)/usb_sil.c
# List ASM source files here
ASRCDIE = $(DEVDIR)/Source/Templates/TrueSTUDIO
ASRC = $(ASRCDIE)/startup_stm32l1xx_md.s
#ASRC = $(ASRCDIE)/startup_stm32l1xx_hd.s
#ASRC += $(ASRCDIE)/startup_stm32l1xx_mdp.s
# List all user directories here
UINCDIR = $(DEVDIR)/Include \
$(CORELIBDIR) \
$(STMSPINCDDIR) \
$(DISCOVERY) \
$(DEVINCDIR) \
$(STMSPINCDDIR) \
$(STMSPSRCDDIR) \
./
# $(STMUSBINCDIR) \
./inc
# List the user directory to look for the libraries here
ULIBDIR =
# List all user libraries here
ULIBS =
# Define optimisation level here
OPT = -Os
#
# End of user defines
#################################################
#
# Define linker script file here
#
ifeq ($(RUN_FROM_FLASH), 0)
LDSCRIPT = $(LINKER)/$(LDFILE)
FULL_PRJ = $(PROJECT)_ram
else
LDSCRIPT = ../Linker/STM32_flash.ld
FULL_PRJ = $(PROJECT)_rom
endif
INCDIR = $(patsubst %,-I%,$(DINCDIR) $(UINCDIR))
LIBDIR = $(patsubst %,-L%,$(DLIBDIR) $(ULIBDIR))
ifeq ($(RUN_FROM_FLASH), 0)
DEFS = $(DDEFS) $(UDEFS) -DRUN_FROM_FLASH=0 -DVECT_TAB_SRAM
else
DEFS = $(DDEFS) $(UDEFS) -DRUN_FROM_FLASH=1
endif
ADEFS = $(DADEFS) $(UADEFS)
OBJS = $(ASRC:.s=.o) $(SRC:.c=.o)
LIBS = $(DLIBS) $(ULIBS)
MCFLAGS = -mcpu=$(MCU)
ASFLAGS = $(MCFLAGS) -g -gdwarf-2 -mthumb -Wa -amhls=$(<:.s=.lst) $(ADEFS)
CPFLAGS = $(MCFLAGS) $(OPT) -gdwarf-2 -mthumb -fomit-frame-pointer -Wall -Wstrict-prototypes -fverbose-asm -Wa,-ahlms=$(<:.c=.lst) $(DEFS)
LDFLAGS = $(MCFLAGS) -mthumb -nostartfiles -T$(LDSCRIPT) -Wl,-Map=$(FULL_PRJ).map,--cref,--no-warn-mismatch $(LIBDIR)
# Generate dependency information
CPFLAGS += -MD -MP -MF .dep\$(@F).d
#
# makefile rules
#
all: $(OBJS) $(FULL_PRJ).elf $(FULL_PRJ).hex $(FULL_PRJ).bin
ifeq ($(RUN_FROM_FLASH), 0)
$(TRGT)size $(PROJECT)_ram.elf
else
$(TRGT)size $(PROJECT)_rom.elf
endif
%o: %c
$(CC) -c $(CPFLAGS) -I . $(INCDIR) $< -o $@
%o: %s
$(AS) -c $(ASFLAGS) $< -o $@
%elf: $(OBJS)
$(CC) $(OBJS) $(LDFLAGS) $(LIBS) -o $@
%hex: %elf
$(HEX) $< $@
%bin: %elf
$(BIN) $< $@
clean:
rm -f $(OBJS)
rm -f $(FULL_PRJ).elf
rm -f $(FULL_PRJ).map
rm -f $(FULL_PRJ).hex
rm -f $(FULL_PRJ).bin
# del $(SRC:.c=.c.bak)
rm -f $(SRC:.c=.lst)
# del $(ASRC:.s=.s.bak)
rm -f $(ASRC:.s=.lst)
rm -fr .dep /S /Q
#
# Include the dependency files, should be the last of the makefile
#
-include $(shell mkdir .dep 2>/dev/null) $(wildcard .dep/*)
# *** EOF ***
Спешу предупредить, что если вы выбрали другой файл линковщика, а т.е. не TrueSTUDIO, то вам следует выбрать соответствующий sturtup файл в переменных ASRCDIE и ASRC. Так же далеко не обязательно собирать все файлы в разделе "used parts of the STM-Library", поэтому можно закомментировать лишние библиотеки, так или иначе, в процессе сборки, по вышедшей ошибке, вы сможете увидеть, какой файл закомментировали зря.
И так. У нас есть все необходимое, чтобы собрать прошивку, поэтому не будем медлить и напишем заветное make all, запуская тем самым инструкцию all в Makefile и компилируя все необходимые файлы для прошивки. Если вы все сделали правильно, то в финале вы получите .elf, .hex, .bin и .map файлы. Их то мы и будем записывать на микроконтроллер.
Немного об отладочной плате. Будучи в линуксе, вы не имете прав на общение с отладочной платой не выполнив команду от root. Поэтому, для упращения процесса работы, нужно создать конфигурационный файлик в /etc/udev/rules.d/. Для рассматриваемой отладочной платы был создан файл /etc/udev/rules.d/90-stm32ldiscovery.rules. С таким содержимым:
ATTRS{idVendor}=="0483", ATTRS{idProduct}=="3748", MODE="0666"
Для обладателей других плат, нужно изменить idVendor и idProduct. Их вы можете просмотреть в выводе команды dmesg после подключения отладочной платы:
[ 4898.094103] usb 2-1.8: USB disconnect, device number 3
[ 4898.932324] usb 2-1.8: new full-speed USB device number 4 using ehci-pci
[ 4899.026137] usb 2-1.8: New USB device found, idVendor=0483, idProduct=3748
[ 4899.026142] usb 2-1.8: New USB device strings: Mfr=1, Product=2, SerialNumber=3
[ 4899.026145] usb 2-1.8: Product: STM32 STLink
[ 4899.026148] usb 2-1.8: Manufacturer: STMicroelectronics
В строке New USB device found, idVendor=0483, idProduct=3748 вы можете увидеть необходимые данные.
Возвратимся к нашей прошивке. Не выходя из директории с проектом, это нужно будет для того чтобы подцепить файлы прошивки, выполним команду
openocd -f /usr/share/openocd/scripts/board/stm32ldiscovery.cfg
Эта команда запустит сервер, подключаясь к которому, в последующем мы сможем прошивать и отлаживать плату.
Откроем другой терминал и выполним команду
telnet localhost 4444
Если openocd был запущен, то вы получите доступ к отладочной плате. Через этот терминал можно производить управление платой. Выполним reset halt и проверим состояние платы с помощью команды poll. Вы можете заметить, что работа программы на плате была остановлена и состояние платы перешло в halted. Полное описание отладчика и команд можно посмотреть в руководстве пользователя OpenOCD. А теперь запишем прошивку:
> flash probe 0
flash size = 128kbytes
flash size = 128kbytes
flash 'stm32lx' found at 0x08000000
> flash write_image erase Имя_файла_прошивки.bin 0x08000000
auto erase enabled
target state: halted
target halted due to breakpoint, current mode: Thread
xPSR: 0x61000000 pc: 0x20000012 msp: 0x20000800
wrote 4096 bytes from file demo.bin in 0.325034s (12.306 KiB/s)
> reset
target state: halted
target halted due to breakpoint, current mode: Thread
xPSR: 0x01000000 pc: 0x08000010 msp: 0x20000800
> exit
Connection closed by foreign host.
Если вы все сделали правильно, то прошивка будет на плате, и вы сможете проверить ее работу, с помощью отладчика. В качестве отладчика можно использовать все тот же Sourcery G++ Lite. Он находится в той же директории, что и другие файлы toolchein-а.
arm-none-eabi-gdb Имя_файла_прошивки.elf
Выполнив эту команду вы попадете в отладчик, наберите target remote :3333, чтобы получить доступ к плате. Работа с отладчиком довольно таки проста, работа с ним описана все в том же руководстве пользователя OpenOCD.
На данном этапе можно запустить программу командой cont и остановить сочетанием клавиш Ctrl+C. После остановки можно посмотреть содержимое какой либо переменной на этом моменте выполнения программы командой print Имя_переменной. Для выхода из отладчика наберите quit.
И так. если вы смогли выполнить все указанные пункты, то можете считать, что справились со всеми настройками по сборке и отладке микроконтроллеров STM32 на Linux.