C
Makefile
ARM
組み込み
STM32

STM32 Nucleo Board実行ファイル作成

STM32 Nucleo Board実行ファイル作成

RaspberryPiでSTM32開発環境の構築でプログラム作成について省略したため、
ここで実行ファイルの作成を行う。

開発ターゲット

STM32 Nucleo Board STM32F303K8

実行ファイル作成に必要なもの

実行ファイル作成は次のような流れになる。
design.png
以上から実行ファイル作成にはスタートアップルーチン、メインプログラム、リンカスクリプト、Makefileが必要になる。

スタートアップルーチン

スタートアップルーチンはSTM32 Nucleo Boardスタートアップルーチンのstartup_stm32f303x8.sを使用する。

リンカスクリプト

リンカスクリプトはSTM32 Nucleo BoardリンカスクリプトのSTM32F303K8Tx_FLASH.ldを使用する。
環境へ取り込むにあたってSTM32F303K8.ldとファイル名を変更。

メインプログラム

このプログラムはLEDを点滅させる(Lチカ)プログラム。
詳細はこの記事では省略するが、GPIO B3が本体のLEDとつながっており、
GPIO B3出力のHigh/Lowを繰り返すことで点滅させる。

main.c
#include "stm32f303x8.h"

void ConfigureTIM6(void)
{
    RCC->APB1ENR |= RCC_APB1ENR_TIM6EN;
    TIM6->PSC = 9999;
    TIM6->ARR = 4200 * 2;
    TIM6->CNT = 0;
    TIM6->CR1 |= TIM_CR1_CEN;
}

void ConfigureGPIOB3(void)
{
    RCC->AHBENR |= RCC_AHBENR_GPIOBEN;

    GPIOB->MODER = GPIO_MODER_MODER3_0;
    GPIOB->OTYPER = 0x0000;
    GPIOB->PUPDR = 0x000000000;
}

// Main -----------------------------------------------------------------------
int main(void)
{
    ConfigureTIM6();
    ConfigureGPIOB3();

    int i = 0;

    // Loop forever
    while(1){
        if(TIM6->SR){
            TIM6->SR = 0;
            if(GPIOB->ODR & GPIO_ODR_3){
                GPIOB->ODR &= ~GPIO_ODR_3;
            }else{
                GPIOB->ODR |= GPIO_ODR_3;
            }
            i++;
        }
    }
    return 0;
}

Makefile

Makefileはソフトウェアまわりの備忘録を参考に作成。

Makefile
# Minimal makefile for STM32F3 Neucleo board.
TARGET := arm-none-eabi

# devtools
CC := $(TARGET)-gcc
LD := $(TARGET)-ld
AS := $(TARGET)-as
OBJCOPY := $(TARGET)-objcopy
STFLASH := st-flash
PORT := /dev/ttyACM0

CFLAGS = -g3 -mcpu=cortex-m4 -mthumb -nostdlib -Os -ffunction-sections -fdata-sections -Wl,--gc-sections -std=c99
INCLUDE = -I./include

#オブジェクトファイルが出力されるディレクトリ
OBJDIR = obj

#Cソースの検索とオブジェクトファイルを出力するディレクトリの設定
SOURCES = $(shell find * -name "*.c")
SRCDIR = $(dir $(SOURCES))
BINDIR = $(addprefix $(OBJDIR)/, $(SRCDIR))

#アセンブラソースの検索とオブジェクトファイルを出力するディレクトリの設定
ASMS = $(shell find * -name "*.s")
ASMDIR = $(dir $(ASMS))
ASMBIN = $(addprefix $(OBJDIR)/, $(ASMDIR))

#オブジェクトファイル群
OBJECTS = $(addprefix $(OBJDIR)/, $(patsubst %.c, %.o, $(SOURCES))) $(addprefix $(OBJDIR)/, $(patsubst %.s, %.o, $(ASMS))) 
DEPENDS = $(OBJECTS:.o=.d)

ifeq "$(strip $(OBJDIR))" ""
    OBJDIR = .
endif

#リンカスクリプト指定
MEMORYMAP = STM32F303K8.ld
#実行ファイル名指定
OBJECTNAME = STM

#サフィックスルール
default :
    @[ -d $(OBJDIR) ] || mkdir -p $(OBJDIR)
    @[ -d "$(BINDIR)" ] || mkdir -p $(BINDIR)
    @[ -d "$(ASMBIN)" ] || mkdir -p $(ASMBIN)
    @make all --no-print-directory

all: $(OBJECTS) $(OBJECTNAME).out $(OBJECTNAME).bin

$(OBJECTNAME).bin: $(OBJECTNAME).out
    $(OBJCOPY) $(OBJECTNAME).out -I ihex -O binary $(OBJECTNAME).bin

$(OBJECTNAME).out: $(OBJECTS)
    $(LD) -T $(MEMORYMAP) $(OBJECTS) -o $(OBJECTNAME).out

$(OBJDIR)/%.o: %.c
    $(CC) $(CFLAGS) $(INCLUDE) -c $< -o $@

$(OBJDIR)/%.o: %.s
    $(AS) -g $< -o $@

.PHONY: clean flash

st-flash: $(OBJECTNAME).bin
    $(STFLASH) write $(OBJECTNAME).bin 0x8000000

clean:
    rm -rf $(OBJDIR) *.out *.bin

実行ファイル作成

makeを実行する。

$ make

上記のMakefileだとSTM.outとSTM.binが作成される。
STM.outは実行ファイル。
STM.binは書き込み用ファイル。

実行

現状、STM.binをツールで書き込んで動かすには至っていない。
STM.outを用いてgdbからloadする。
実行するとLEDが点滅した!!

4A1F4CAA-6A7E-4665-AFC6-44CFB6E41063.jpeg

ソースコード

開発をするにあたってGithubにソースをおいてみた。
mitazet/stm32/v1

参考サイト

yuki-sato.com