Mac搭建STM32编译及调试工具(含led-demo)

因为一些原因,打算温习一下多年不碰的嵌入式开发,故而翻出了积灰的山寨版J-Link V8和STM32f103zet6核心板。由于目前使用的是Mac电脑,而自己又不想使用虚拟机,故而便有了如下折腾~~~

前言

在Windows上有IAR、Keil等强大的IDE,但在Mac上却什么都没有。 可能使用Eclipse+插件的形式就算是最好的选择了,只是个人对Eclipse不太感冒。经过一番搜寻,最终在以 编辑器 + gcc-arm-none-eabi + openOCD的模式完成了星星点灯

编译工具

工具地址 : GNU Arm Embedded Toolchain

直接下载Mac版本(当前版本为:gcc-arm-none-eabi-7-2017-q4-major-mac.tar.bz2),解压缩到一个目录。

➜  gcc-arm-none-eabi pwd
/Users/bingo/EmbeddedDev/toolchain/gcc-arm-none-eabi
➜ gcc-arm-none-eabi tree -L 2
.
├── arm-none-eabi
│   ├── bin
│   ├── include
│   ├── lib
│   └── share
├── bin
│   ├── arm-none-eabi-addr2line
│   ├── arm-none-eabi-ar
│   ├── arm-none-eabi-as
│   ├── arm-none-eabi-c++
│   ├── arm-none-eabi-c++filt
│   ├── arm-none-eabi-cpp
│   ├── arm-none-eabi-elfedit
│   ├── arm-none-eabi-g++
│   ├── arm-none-eabi-gcc
│   ├── arm-none-eabi-gcc-7.2.1
│   ├── arm-none-eabi-gcc-ar
│   ├── arm-none-eabi-gcc-nm
│   ├── arm-none-eabi-gcc-ranlib
│   ├── arm-none-eabi-gcov
│   ├── arm-none-eabi-gcov-dump
│   ├── arm-none-eabi-gcov-tool
│   ├── arm-none-eabi-gdb
│   ├── arm-none-eabi-gdb-py
│   ├── arm-none-eabi-gprof
│   ├── arm-none-eabi-ld
│   ├── arm-none-eabi-ld.bfd
│   ├── arm-none-eabi-nm
│   ├── arm-none-eabi-objcopy
│   ├── arm-none-eabi-objdump
│   ├── arm-none-eabi-ranlib
│   ├── arm-none-eabi-readelf
│   ├── arm-none-eabi-size
│   ├── arm-none-eabi-strings
│   └── arm-none-eabi-strip
├── lib
│   ├── gcc
│   ├── libcc1.0.so
│   └── libcc1.so -> libcc1.0.so
└── share
├── doc
└── gcc-arm-none-eabi

11 directories, 31 files

为了便于使用,将bin目录添加到系统PATH中,即添加如下指令到.zshrc文件。

export PATH=/Users/bingo/EmbeddedDev/toolchain/gcc-arm-none-eabi/bin:$PATH

检验安装

➜  ~ arm-none-eabi-gcc --version
arm-none-eabi-gcc (GNU Tools for Arm Embedded Processors 7-2017-q4-major) 7.2.1 20170904 (release) [ARM/embedded-7-branch revision 255204]
Copyright (C) 2017 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

至此,编译工具安装完成。

调试工具

鉴于我手头的JTAG调试工具是J-Link,所以有两个工具可选.

  • SEGGER官方工具(J-Link Commander)

  • 开源调试工具 (openOCD)

如果使用的是官版J-Link,使用J-Link Commander可能会比较好。但我看了下淘宝上就没有正版的JLink,全是克隆版。
因为当前版本的工具有license校验。没有正确的SN码,那么将不能使用,提示“The connected J-Link is defective. Proper operation cannot be guaranteed. Please get in touch with support@segger.com and send a screenshot of this dialog with the e-mail.”。
如下:

网上有很多所谓的攻略全都没用,除非使用低版本工具。也正是在这个过程中,我按照那些个教程重刷了JLink固件,这又是一堆坑。(后文有记录)

最终的情况就是弃用了这个工具,使用openOCD。

openOCD

简单来讲,openOCD这个开源工具就是一个万能调试器,兼容如ST-Link,J-Link等等众多硬件。如果需要使用多种调试工具的话,那么还是直接使用这个工具更好。

官方并没有提供编译好的安装包,所以下载了源码进行安装,结果我安装的时候需要遇到了一些问题。

  • 配置问题

按照INSTALL文件中的./configure && make && make install 是没办法成功的。进一步查看冗长的说明,./configure必须带参数才行。

./configure --enable-maintainer-mode --enable-jlink 至少需要带上--enable-jlink

成功的时候,结果如下,至少得看到SEGGER J-Link Programmer yes才行。

OpenOCD configuration summary
--------------------------------------------------
MPSSE mode of FTDI based devices yes (auto)
ST-Link JTAG Programmer yes (auto)
TI ICDI JTAG Programmer yes (auto)
Keil ULINK JTAG Programmer yes (auto)
Altera USB-Blaster II Compatible yes (auto)
Versaloon-Link JTAG Programmer yes (auto)
OSBDM (JTAG only) Programmer yes (auto)
eStick/opendous JTAG Programmer yes (auto)
Andes JTAG Programmer yes (auto)
USBProg JTAG Programmer yes (auto)
Raisonance RLink JTAG Programmer yes (auto)
Olimex ARM-JTAG-EW Programmer yes (auto)
CMSIS-DAP Compliant Debugger yes (auto)
Altera USB-Blaster Compatible yes (auto)
ASIX Presto Adapter yes (auto)
OpenJTAG Adapter yes (auto)
SEGGER J-Link Programmer yes

  • make报错
    openocd-0.10.0 make
    Makefile:4252: warning: overriding commands for target `check-recursive'
    Makefile:3665: warning: ignoring old commands for target `check-recursive'
    cd . && /bin/sh /Users/bingo/EmbeddedDev/toolchain/openocd-0.10.0/missing automake-1.15 --gnu
    configure.ac:16: error: version mismatch. This is Automake 1.15.1,
    configure.ac:16: but the definition used by this AM_INIT_AUTOMAKE
    configure.ac:16: comes from Automake 1.15. You should recreate
    configure.ac:16: aclocal.m4 with aclocal and run automake again.
    Makefile.am:46: warning: wildcard $(srcdir: non-POSIX variable name
    Makefile.am:46: (probably a GNU make extension)
    WARNING: 'automake-1.15' is probably too old.
    You should only need it if you modified 'Makefile.am' or
    'configure.ac' or m4 files included by 'configure.ac'.
    The 'automake' program is part of the GNU Automake package:
    <http://www.gnu.org/software/automake>
    It also requires GNU Autoconf, GNU m4 and Perl in order to run:
    <http://www.gnu.org/software/autoconf>
    <http://www.gnu.org/software/m4/>
    <http://www.perl.org/>
    make: *** [Makefile.in] Error 1

也许我降级automake的版本可以通过,不过灵机一动,试了试:

brew install openocd

结果困了许久的问题,一下子就解决了。 想抽自己巴掌,,, 果然homebrew才是简单正确的姿势。

除了用命令行直接安装以外,还可以考虑从https://github.com/gnu-mcu-eclipse/openocd/releases下载非官方的安装包。 没试过,但应该没问题。

openOCD使用

  • 交互模式
    openocd -f interface/jlink.cfg -f target/stm32f1x.cfg

带上调试器和目标芯片相关的cfg文件即可。

interfacetarget目录位于/usr/local/Cellar/open-ocd/0.10.0/share/openocd/scripts/下,里面存放了支持的Debuger和Chip。

openocd -f interface/jlink.cfg -f target/stm32f1x.cfg
Open On-Chip Debugger 0.10.0
Licensed under GNU GPL v2
For bug reports, read
http://openocd.org/doc/doxygen/bugs.html
Info : auto-selecting first available session transport "jtag". To override use 'transport select <transport>'.
adapter speed: 1000 kHz
adapter_nsrst_delay: 100
jtag_ntrst_delay: 100
none separate
cortex_m reset_config sysresetreq
Info : No device selected, using first device.
Info : J-Link ARM V8 compiled Nov 28 2014 13:44:46
Info : Hardware version: 8.00
Info : VTarget = 3.325 V
Info : clock speed 1000 kHz
Info : JTAG tap: stm32f1x.cpu tap/device found: 0x3ba00477 (mfg: 0x23b (ARM Ltd.), part: 0xba00, ver: 0x3)
Info : JTAG tap: stm32f1x.bs tap/device found: 0x06414041 (mfg: 0x020 (STMicroelectronics), part: 0x6414, ver: 0x0)
Info : stm32f1x.cpu: hardware has 6 breakpoints, 4 watchpoints

如上显示表示连接正常,系统后台开启了4444的端口。使用telnet连接到4444端口后便可以进行交互。

➜  ~ telnet localhost 4444
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
Open On-Chip Debugger
> help
# 查看支持的命令,超多,此处不列出。
> halt # 挂起目标芯片
target halted due to debug-request, current mode: Thread
xPSR: 0x21000000 pc: 0x08008dca msp: 0x2000ffe8
> flash write_image erase stm32_LED.hex # 烧录flash
auto erase enabled
device id = 0x10036414
flash size = 512kbytes
Padding image section 0 with 1410 bytes
wrote 40960 bytes from file stm32_LED.hex in 1.682081s (23.780 KiB/s)
> reset # 复位
JTAG tap: stm32f1x.cpu tap/device found: 0x3ba00477 (mfg: 0x23b (ARM Ltd.), part: 0xba00, ver: 0x3)
JTAG tap: stm32f1x.bs tap/device found: 0x06414041 (mfg: 0x020 (STMicroelectronics), part: 0x6414, ver: 0x0)
> exit # 退出连接
Connection closed by foreign host.

  • 命令模式

把交互模式中执行过的命令依次添加到命令选项中即可。

openocd -f interface/jlink.cfg -f target/stm32f1x.cfg -c init -c halt -c "flash write_image erase ./stm32_LED.hex" -c reset -c shutdown

J-Link固件烧录

原本我J-Link的好好的,但为了解决J-Link Commander校验克隆板的问题,按照网上的教程给清空了(教程很多,自行搜索),然而最后也没卵用。期间多次重写烧录J-Link固件。PS:我的J-Link版本是V8,内部芯片为:AT91SAM7S64

  • 烧录工具

在Windows和Linux上有ATMEL的SAM-BA编程器,但没有Mac版本的,理论上Linux版本的可以拿过来安装,但貌似需要X11。

另外一个工具:BOSSA https://github.com/shumatech/BOSSA

下载安装即可。

  • 固件

CSDN上有不少固件,但都需要积分下载。 这里提供一个能用的:jlink-v8cracksn.bin

  • 烧录固件

使用BOSSA的界面版工具挺好用的,但不知怎么回事(疑似在选择设备的时候,选中了蓝牙),就闪退,后来一直闪退。 最后只能使用命令行进行刷如固件。

➜ ~ ll /dev/tty.*       # 找到设备
crw-rw-rw- 1 root wheel 21, 0 Jan 16 04:17 /dev/tty.Bluetooth-Incoming-Port
crw-rw-rw- 1 root wheel 21, 0 Jan 16 04:17 /dev/tty.usbmodem1411 # j-link设备

➜ ~ bossac -u -e -w -v -b jlink-v8cracksn.bin -p tty.usbmodem1411

之后安装网上的说法,在JLinkExe中执行exec setsn=20180116(随便数值)来写入sn,然而还是不行。

最后我重新打开JLinkExe接受了固件升级确认。

如此虽然没解决任何问题,但还好J-Link并没被我搞成砖头。

星星点灯demo

stm32相关的资料可以到http://www.stmcu.org查找并下载,比st官网方便。

最关键的是下载 stsw-stm32054 - 标准外围库,这是目前最新的固件库了,尽管里面很多内容还是2011年的。

创建项目

新建一个项目目录,并将固件中的文件导入

➜  LED tree
.
├── CMSIS
│   ├── core_cm3.c
│   ├── core_cm3.h
│   ├── stm32f10x.h
│   ├── system_stm32f10x.c
│   └── system_stm32f10x.h
├── FWLib
│   ├── inc
│   │   ├── misc.h
│   │   ├── stm32f10x_gpio.h
│ │ └── .... # 省略
│   └── src
│   ├── misc.c
│   ├── stm32f10x_gpio.c
│ └── .... # 省略
├── Makefile
├── Script
│   └── stm32f10e_flash.ld
├── Startup
│   └── startup_stm32f10x_hd.s
└── User
   ├── main.c
   ├── stm32f10x_conf.h
   ├── stm32f10x_it.c
   └── stm32f10x_it.h

main.c

#include "stm32f10x.h"

GPIO_InitTypeDef GPIO_InitStructure;

void delay(int n)
{
n =n * 1000000;
while(n--){
}
}

int main(void)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_Init(GPIOC, &GPIO_InitStructure);

while (1)
{
GPIO_ResetBits(GPIOC,GPIO_Pin_13);
delay(1);
GPIO_SetBits(GPIOC,GPIO_Pin_13);
delay(1);
}
}

编译 & makefile

以前从来都是在IDE中一键完成的工作,现在需要手工来做,简直了。。。。

编译文件必然用到Makefile,网上最火爆的资料 跟我一起写Makefile。 多多少少必须得看看,不然绝对懵逼的。

经过好一番折腾,终于写出了Makefile

# 生成的文件名<项目名>
PROJECT = stm32_LED

# 定义编译工具
export CC = arm-none-eabi-gcc
export AS = arm-none-eabi-as
export LD = arm-none-eabi-ld
export AR = arm-none-eabi-ar
export OBJCP = arm-none-eabi-objcopy

# 定义文件格式和文件名
TARGET := $(PROJECT)
TARGET_ELF := $(TARGET).elf
TARGET_BIN := $(TARGET).bin
TARGET_HEX := $(TARGET).hex
OBJCPFLAGS_ELF_TO_BIN = -Obinary
OBJCPFLAGS_ELF_TO_HEX = -Oihex
OBJCPFLAGS_BIN_TO_HEX = -Ibinary -Oihex

# 定义路径
TOP = .
INC_DIR = -I $(TOP)/CMSIS -I $(TOP)/Startup -I $(TOP)/FWLib/inc -I $(TOP)/User

CCFLAGS = -Wall -g -mcpu=cortex-m3 -mthumb -D STM32F10X_HD -D USE_STDPERIPH_DRIVER $(INC_DIR) -O0 -std=gnu11 # -W
ASFLAGS = -W -g -mcpu=cortex-m3 -mthumb # —Wall会产生大量信息
C_SRC = $(shell find . -name '*.c') # 如果这样报core_m3.c编译错误的话,改用下一句。具体问题,后文说明。
#C_SRC = $(shell find User FWLib/src -name '*.c')

ASM_SRC = $(TOP)/Startup/startup_stm32f10x_hd.s # 使用RIDE7或Atollic项目中的s文件。 old方法:.S大写?
LDSCRIPT= $(TOP)/Script/stm32f10e_flash.ld
LDFLAGS+= -T $(LDSCRIPT)
LDFLAGS+= -L /Users/bingo/EmbeddedDev/toolchain/gcc-arm-none-eabi/arm-none-eabi/lib/thumb
LDFLAGS+= -L /Users/bingo/EmbeddedDev/toolchain/gcc-arm-none-eabi/lib/gcc/arm-none-eabi/7.2.1/thumb

C_OBJ = $(C_SRC:%.c=%.o)
ASM_OBJ = $(ASM_SRC:%.s=%.o)

.PHONY: clean all update

all:$(TARGET).hex $(TARGET).bin
@echo "\n**************************编译完成**************************\n"

$(TARGET).hex:$(TARGET).elf
$(OBJCP) -Oihex $< $@

$(TARGET).bin:$(TARGET).elf
$(OBJCP) -Obinary $< $@

$(TARGET).elf:$(C_OBJ) $(ASM_OBJ)
$(LD) $^ $(LDFLAGS) -o $@

$(C_OBJ):%.o:%.c
# @echo "编译.c文件"
# @echo $(C_SRC)
$(CC) $(CCFLAGS) -c $< -o $@

$(ASM_OBJ):%.o:%.s
# @echo "编译.s文件"
# @echo $(ASM_SRC)
$(AS) $(ASFLAGS) -c $< -o $@

clean:
rm -f $(C_OBJ) $(ASM_OBJ)
@echo "Clean done"

update:$(TARGET).hex
openocd -f interface/jlink.cfg -f target/stm32f1x.cfg -c init -c halt -c "flash write_image erase $(TOP)/$(TARGET).hex" -c reset -c shutdown
@echo "\n**************************\n\t程序下载完成\n**************************\n"

两个大坑:

  • startup_stm32f10x_hd.s汇编失败
    
    汇编startup_stm32f10x_hd.s文件时,总是提示 Error: junk at end of line, first unrecognized character is * 之类的错误。

看起来像是汇编文件中的”;”注释没有生效。网上比较靠谱的说明:stackoverflow

如果在汇编中使用宏或C注释,就必须使用C预处理器预处理源文件。 C预处理器会删除注释并解释宏。 如果源文件名以.S(大写)结尾,GNU汇编程序会自动运行C预处理器。

update in 2019年05月07日

经过测试,s文件有两种写法。MDK-ARM和EWARM相同,RIDE7和Atollic相同,此处使用的arm-none-eabi-as(GUN)适用于后者。 故而选用RIDE7示例项目的s文件即可。

  • core_m3.c 编译失败

错误提示如下:

arm-none-eabi-gcc -Wall -g -mcpu=cortex-m3 -mthumb -D STM32F10X_HD -D USE_STDPERIPH_DRIVER -I ./CMSIS -I ./Startup -I ./FWLib/inc -I ./User -O0 -std=gnu11 -c CMSIS/core_cm3.c -o CMSIS/core_cm3.o
/var/folders/kp/4lz3l_7j64dc_lzvdsfzdg500000gn/T//cccfwCep.s: Assembler messages:
/var/folders/kp/4lz3l_7j64dc_lzvdsfzdg500000gn/T//cccfwCep.s:894: Error: registers may not be the same -- `strexb r3,r2,[r3]'
/var/folders/kp/4lz3l_7j64dc_lzvdsfzdg500000gn/T//cccfwCep.s:947: Error: registers may not be the same -- `strexh r3,r2,[r3]'
make: *** [CMSIS/core_cm3.o] Error 1

两个解决办法:

  • 注释core_m3.c文件中的两个相关函数:uint32_t __STREXB(uint8_t value, uint8_t *addr)uint32_t __STREXH(uint16_t value, uint16_t *addr) ,或者直接不编译core_m3.c文件。 因为本身这两个函数就不太能用到。

  • 按照大咖的指示修改core_m3.c文件。 https://gist.github.com/timbrom/1942280

    -   __ASM volatile ("strexb %0, %2, [%1]" : "=r" (result) : "r" (addr), "r" (value) );
    + __ASM volatile ("strexb %0, %2, [%1]" : "=&r" (result) : "r" (addr), "r" (value) );

    - __ASM volatile ("strexh %0, %2, [%1]" : "=r" (result) : "r" (addr), "r" (value) );
    + __ASM volatile ("strexh %0, %2, [%1]" : "=&r" (result) : "r" (addr), "r" (value) );

make 一下,贼顺溜。。。
make update一下,编译烧录一键完成。

➜  LED make update
openocd -f interface/jlink.cfg -f target/stm32f1x.cfg -c init -c halt -c "flash write_image erase ./stm32_LED.hex" -c reset -c shutdown
Open On-Chip Debugger 0.10.0
Licensed under GNU GPL v2
For bug reports, read
http://openocd.org/doc/doxygen/bugs.html
Info : auto-selecting first available session transport "jtag". To override use 'transport select <transport>'.
adapter speed: 1000 kHz
adapter_nsrst_delay: 100
jtag_ntrst_delay: 100
none separate
cortex_m reset_config sysresetreq
Info : No device selected, using first device.
Info : J-Link ARM V8 compiled Nov 28 2014 13:44:46
Info : Hardware version: 8.00
Info : VTarget = 3.325 V
Info : clock speed 1000 kHz
Info : JTAG tap: stm32f1x.cpu tap/device found: 0x3ba00477 (mfg: 0x23b (ARM Ltd.), part: 0xba00, ver: 0x3)
Info : JTAG tap: stm32f1x.bs tap/device found: 0x06414041 (mfg: 0x020 (STMicroelectronics), part: 0x6414, ver: 0x0)
Info : stm32f1x.cpu: hardware has 6 breakpoints, 4 watchpoints
target halted due to debug-request, current mode: Thread
xPSR: 0x21000000 pc: 0x08008dc8 msp: 0x2000ffe8
auto erase enabled
Info : device id = 0x10036414
Info : flash size = 512kbytes
Info : Padding image section 0 with 1410 bytes
wrote 40960 bytes from file ./stm32_LED.hex in 1.688355s (23.692 KiB/s)
Info : JTAG tap: stm32f1x.cpu tap/device found: 0x3ba00477 (mfg: 0x23b (ARM Ltd.), part: 0xba00, ver: 0x3)
Info : JTAG tap: stm32f1x.bs tap/device found: 0x06414041 (mfg: 0x020 (STMicroelectronics), part: 0x6414, ver: 0x0)
shutdown command invoked

**************************
程序下载完成
**************************

后记

至此,折腾完毕!

虽然我不太喜欢eclipse,但不可否认,在Mac平台下进行arm开发,那可能是最好的平台了,还是可以考虑下的。

https://gnu-mcu-eclipse.github.io