LibOpenCM3(一) Linux下命令行开发环境配置
目录
本文默认使用 Linux 环境, 硬件为 STM32F103 系列开发板
LibOpenCM3 介绍
LibOpenCM3 是GPL协议(LGPL3)的Cortex-M系列的固件库, 支持stm32、atmel、nxp系列单片机. 这个固件库对标的是 CMSIS, 但是比 CMSIS 提供更多的方法接口, 实现度介于 CMSIS 和 SPL 之间. 对于常见的 STM32F1 系列, 代码已经基本稳定.
- 项目地址
https://github.com/libopencm3/libopencm3 - 项目示例
https://github.com/libopencm3/libopencm3-examples - WIKI
https://github.com/libopencm3/libopencm3/wiki - API文档
http://libopencm3.org/docs/latest/html/
开发环境
硬件部分
- STM32F103 开发板
- ST-Link V2
软件部分
- LibOpenCM3
https://github.com/libopencm3/libopencm3 - LibOpenCM3项目模板
https://github.com/libopencm3/libopencm3-template - GNU Arm Embedded Toolchain
下载地址 - stlink linux工具, 包含st-flash,st-info等命令
https://github.com/stlink-org/stlink/blob/develop/doc/tutorial.md- --flash=128k 参数可以指定flash大小, 例如覆盖 STM32F103C8T6 默认的 64k 大小设置. 取值可以使用 十进制(128k), 八进制 0200k, 或者十六进制 0x80k.
- --reset 在写入结束后触发重置
- --connect-under-reset 重置状态下连接. 使用这个选项可以在用户代码执行前连接MCU, 当目标MCU上的用户代码将MCU置于sleep状态, 或禁用了调试接口导致无法连接时特别有用.
LibOpenCM3 项目模板
导出 libopencm3 可以单独编译, 但是配置为完整的项目还需要添加用户代码和Makefile, 因为 LibOpenCM3 已经提供了立即可用的项目模板, 可以直接用模板提供的环境进行开发
导出模板
git clone --recurse-submodules https://github.com/libopencm3/libopencm3-template.git cd libopencm3-template/ # 这一步需要前面的 arm-none-eabi-gcc 工具链已经配置到 PATH # 编译 make -C libopencm3
这一步会编译 libopencm3
- 在 libopencm3/lib 目录下生成全部型号的 .a 库文件
- 在 libopencm3/lib/stm32 目录下, 对应 f0, f1, ..., f7 等各个目录下生成对应型号的 ld 文件
如果前面没有将 arm-none-eabi-gcc 添加到PATH, 需要修改一下 libopencm3/Makefile, 将 PREFIX 修改为
PREFIX ?= /opt/gcc-arm/gcc-arm-none-eabi-10.3-2021.10/bin/arm-none-eabi-
注: 在当前的模板项目中, libopencm3不是最新版本, 版本号 cb0661f81de5b1cae52ca99c7b5985b678176db7 对应的是2020-02-16的版本, 这个版本在lib/stm32/fx 目录下依然有各个型号的ld文件, 而这些文件实际上在 2020-11-29 的提交中已经删除了. 具体的说明可以点开查看. 当前模板的Makefile实际上使用的是后者的编译方式生成项目的ld文件.
编辑用户项目, 在编辑之前, 需要修改 my-project 目录下的 Makefile, 将 DEVICE 修改为自己的 STM32 型号
# TODO - you will need to edit these two lines! DEVICE=stm32f103c6t6
填入的型号如果正确, 会在编译时生成对应的ld文件, 例如对应上面的就是 generated.stm32f103c6t6.ld
如果前面没有将 arm-none-eabi-gcc 添加到PATH, 需要修改一下 my-project/Makefile, 添加 PREFIX 定义
PREFIX ?= /opt/gcc-arm/gcc-arm-none-eabi-10.3-2021.10/bin/arm-none-eabi-
编译
make -C my-project
这时候在 my-project 目录下会产生以下文件
total 172 -rwxrwxr-x 1 milton milton 1492 Feb 20 23:55 awesomesauce.bin* -rwxrwxr-x 1 milton milton 276952 Feb 20 23:55 awesomesauce.elf* drwxrwxr-x 2 milton milton 4096 Feb 20 23:55 bin/ -rw-rw-r-- 1 milton milton 1108 Feb 20 23:55 generated.stm32f103c6t6.ld -rw-rw-r-- 1 milton milton 493 Feb 20 23:38 Makefile -rw-rw-r-- 1 milton milton 2099 Feb 20 23:42 my-project.c
其中 awesomesauce.bin 是用于烧录的文件
通过 arm-none-eabi-size 查看编译结果的内存结构.
$ arm-none-eabi-size awesomesauce.elf text data bss dec hex filename 1480 12 0 1492 5d4 awesomesauce.elf
其中
- text 是占用的flash空间
- data 初始化占用内存大小
- bss 全局分配的内存大小
- dec和hex 十进制和十六进制表示的总大小
演示示例
下面用一个闪灯的示例把开发环境跑一遍.
用户代码
将 my-project 目录下的 my-project.c 内容修改为
#include
#include #include #include #ifndef ARRAY_LEN #define ARRAY_LEN(array) (sizeof((array))/sizeof((array)[0])) #endif #define LED1_PORT GPIOC #define LED1_PIN GPIO13 static void gpio_setup(void) { /* Enable GPIO clock for leds. */ rcc_periph_clock_enable(RCC_GPIOC); /* Enable led as output */ gpio_set_mode( LED1_PORT, GPIO_MODE_OUTPUT_50_MHZ, GPIO_CNF_OUTPUT_PUSHPULL, LED1_PIN); gpio_set(LED1_PORT, LED1_PIN); } static void tim_setup(void) { /* Enable TIM2 clock. */ rcc_periph_clock_enable(RCC_TIM2); /* Enable TIM2 interrupt. */ nvic_enable_irq(NVIC_TIM2_IRQ); /* Reset TIM2 peripheral to defaults. */ rcc_periph_reset_pulse(RST_TIM2); /* Timer global mode: * - No divider * - Alignment edge * - Direction up * (These are actually default values after reset above, so this call * is strictly unnecessary, but demos the api for alternative settings) */ timer_set_mode(TIM2, TIM_CR1_CKD_CK_INT, TIM_CR1_CMS_EDGE, TIM_CR1_DIR_UP); /* Disable preload. */ timer_disable_preload(TIM2); timer_continuous_mode(TIM2); timer_set_prescaler(TIM2, 36000); // Clock counts every 0.5 msec timer_set_period(TIM2, 2000); // 2000 * 0.5 msec => 1 sec /* Counter enable. */ timer_enable_counter(TIM2); /* Enable Channel 1 compare interrupt to recalculate compare values */ timer_enable_irq(TIM2, TIM_DIER_CC1IE); } /** * ISR method defined in libopencm3/include/libopencm3/stm32/f1/nvic.h */ void tim2_isr(void) { if (timer_get_flag(TIM2, TIM_SR_CC1IF)) { /* Clear compare interrupt flag. */ timer_clear_flag(TIM2, TIM_SR_CC1IF); /* Toggle LED to indicate compare event. */ gpio_toggle(LED1_PORT, LED1_PIN); } } int main(void) { // Setup main clock, using external 8MHz crystal rcc_clock_setup_in_hse_8mhz_out_72mhz(); gpio_setup(); tim_setup(); while (1); return 0; } 上面的代码, 用TIM2定时, 触发板载C13对应的LED每秒切换亮灭状态
编译
使用前面配置好的开发环境
make -C my-project
写入
将开发板接上ST-Link接上PC
写入, 0x800 0000 是 STM32F103 的Flash空间起始地址
st-flash write ./awesomesauce.bin 0x8000000 # 会看到包含如下文字的输出 2022-02-21T00:00:42 INFO common.c: STM32F1xx_LD: 10 KiB SRAM, 32 KiB flash in at least 1 KiB pages. file ./awesomesauce.bin md5 checksum: 363668176fa21306a846725b7db2079, stlink checksum: 0x0001fe1e 2022-02-21T00:00:42 INFO common_flash.c: Attempting to write 1492 (0x5d4) bytes to stm32 address: 134217728 (0x8000000) -> Flash page at 0x8000000 erased (size: 0x400) -> Flash page at 0x8000400 erased (size: 0x400) 2022-02-21T00:00:42 INFO flashloader.c: Starting Flash write for VL/F0/F3/F1_XL 2022-02-21T00:00:42 INFO flash_loader.c: Successfully loaded flash loader in sram 2022-02-21T00:00:42 INFO flash_loader.c: Clear DFSR 2022-02-21T00:00:42 INFO flash_loader.c: Clear CFSR 2022-02-21T00:00:42 INFO flash_loader.c: Clear HFSR 2/ 2 pages written 2022-02-21T00:00:42 INFO common_flash.c: Starting verification of write complete 2022-02-21T00:00:42 INFO common_flash.c: Flash written and verified! jolly good!
此时需要手动按一下开发板的 RESET 键, 程序才会开始执行, 如果需要自动重置, 使用下面的命令
st-flash --reset write ./awesomesauce.bin 0x8000000
其它命令
查看开发板信息
st-info --probe # 会看到包含如下文字的输出(当前这块测试用的是 stm32f103c6t6) Found 1 stlink programmers version: V2J37S7 serial: 56FF6B064966485627461667 flash: 32768 (pagesize: 1024) sram: 10240 chipid: 0x412
擦除
st-flash erase # 会看到包含如下文字的输出 2022-02-21T00:00:12 INFO common.c: STM32F1xx_LD: 10 KiB SRAM, 32 KiB flash in at least 1 KiB pages. Mass erasing
参考
- https://bdebyl.net/post/stm32-part0/
- https://bdebyl.net/post/stm32-part1/
- https://rhye.org/post/stm32-with-opencm3-0-compiling-and-uploading/
- https://thomas.spurden.name/blog/stm-start/