LibOpenCM3(一) Linux下命令行開發環境配置

目錄

本文使用 Linux 環境, 硬體為 STM32F103 系列開發板

LibOpenCM3 介紹

LibOpenCM3 是GPL協議(LGPL3)的Cortex-M系列的韌體庫, 支援stm32、atmel、nxp系列單片機. 這個韌體庫對標的是 CMSIS, 但是比 CMSIS 提供更多的方法介面, 實現度介於 CMSIS 和 SPL 之間. 對於常見的 STM32F1 系列, 程式碼已經基本穩定.

開發環境

硬體部分

  • STM32F103 開發板
  • ST-Link V2

軟體部分

環境配置

GNU Arm Embedded Toolchain 工具鏈

通過前面的地址下載最新版本, 根據自己的系統架構選擇合適的架構版本

# 解壓
tar xjf gcc-arm-none-eabi-10.3-2021.10-x86_64-linux.tar.bz2
# 放到/opt下並設置許可權
sudo mv gcc-arm-none-eabi-10.3-2021.10 /opt/gcc-arm/
cd /opt/gcc-arm/
sudo chown -R root:root gcc-arm-none-eabi-10.3-2021.10/

加到PATH

export PATH="/opt/gcc-arm/gcc-arm-none-eabi-10.3-2021.10/bin:$PATH"

檢查版本

$ arm-none-eabi-gcc --version
arm-none-eabi-gcc (GNU Arm Embedded Toolchain 10.3-2021.10) 10.3.1 20210824 (release)
Copyright (C) 2020 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.

stlink,st-flash,st-info

需要先安裝 libusb-1.0-0-dev

sudo apt install libusb-1.0-0-dev

編譯安裝

git clone //github.com/stlink-org/stlink.git
cd stlink/
make
cd build/Release/
sudo make install

檢查

$ st-flash  --version
v1.7.0-184-g468b1d2
$ st-info --version
Failed to parse flash type or unrecognized flash type
v1.7.0-184-g468b1d2

st-flash 使用說明 //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 //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 文件

編輯用戶項目, 在編輯之前, 需要修改 my-project 目錄下的 Makefile, 將 DEVICE 修改為自己的 STM32 型號

# TODO - you will need to edit these two lines!
DEVICE=stm32f103c6t6

填入的型號如果正確, 會在編譯時生成對應的ld文件, 例如對應上面的就是 generated.stm32f103c6t6.ld

編譯

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 <libopencm3/cm3/nvic.h>
#include <libopencm3/stm32/rcc.h>
#include <libopencm3/stm32/gpio.h>
#include <libopencm3/stm32/timer.h>

#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

參考