STM32 в Linux

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.