今回はWCH公式のSDKのビルド方法を解説します。公式開発環境のMounRiver Studio向けではあるのですが、プレーンなGCCからでも取り扱うことができます。
このSDKはPlatformIOやArduino環境でも使われているので、その構造を理解することで、それらの開発環境への理解も深まることと思います。
本記事はアドベントカレンダー「CH32V203」に参加しています。
概要
ここで「SDK」と呼んでいるものは、以下のレポジトリのことです。
純粋なSDKとして配布されているわけではなく、各種の資料の中にサンプルプログラムも入っていて、その一部を参照する形となります。
SDKとして利用できる部分としては、大きく3つに分けられます。
- スタートアップコード(アセンブリ言語)
- main()を呼び出す前の初期設定部分
- リンカースクリプト
- メモリ領域の定義
- ペリフェラル(周辺機能)を扱うライブラリ(C言語)
実用上は3つ目のペリフェラルライブラリを使うのがメインになります。
ペリフェラルライブラリは、CH32V203の構造のリファレンスであるSTM32F103のStandard Peripheral Library (SPL)を模倣したものになっています。STM32ではその後、HALやLLという新しい世代のライブラリがリリースされていますが、CH32V203のはSPLです。
SPLをそのままトレースしているので、STM32F103の資料がけっこう役に立ったりします。
SDKを使うためのMakefile
SDKを使って独自のプログラムをビルドするMakefileを紹介します。
ソースコード全体はこちら。
# 生成するファームウェアのファイル名
TARGET_ELF := main.elf
# .bin形式も生成する
TARGET_BIN := $(TARGET_ELF:.elf=.bin)
# 各シンボルのアドレスとサイズがわかるmapファイルも生成
TARGET_MAP := $(TARGET_ELF).map
# SDKのソースディレクトリ
SDK_DIR := ch32v20x/EVT/EXAM/SRC
# リンカースクリプト
LINKER_SCRIPT := $(SDK_DIR)/Ld/Link.ld
# 自分のプログラムのソースコード
APP_SRCS := main.c \
system_ch32v20x.c
# SDK内の必要なコードを追加する
SDK_SRCS := ch32v20x_rcc.c \
ch32v20x_pwr.c \
ch32v20x_gpio.c \
ch32v20x_usart.c
# ディレクトリパスを一括で追加
SDK_SRCS := $(addprefix $(SDK_DIR)/Peripheral/src/,$(SDK_SRCS))
# 便利な関数が定義されている debug.c を追加
SDK_SRCS += $(SDK_DIR)/Debug/debug.c
# マイコンの初期化コード
STARTUP_SRC := $(SDK_DIR)/Startup/startup_ch32v20x_D6.S
# ヘッダーファイルの探索パスを指定
INCLUDE_DIRS := . \
$(SDK_DIR)/Core/ \
$(SDK_DIR)/Peripheral/inc \
$(SDK_DIR)/Debug
# ツールチェーンのトリプレット
TRIPLET ?= riscv-none-elf-
# コンパイラ
CC := $(TRIPLET)gcc
# バイナリサイズを表示するツール
SIZE := $(TRIPLET)size
# ファイル形式を変換するツール
OBJCOPY := $(TRIPLET)objcopy
# マイコンの動作クロックを指定(system_ch32v20x.cを参照)
CFLAGS += -DSYSCLK_FREQ_144MHz_HSI=144000000
# 最適化レベルと警告表示
CFLAGS += -Os -flto -Wall
# RISC-Vの命令セットを指定
CFLAGS += -mabi=ilp32 -march=rv32imac_zicsr
# その他便利なオプション
CFLAGS += -mcmodel=medany -ffat-lto-objects -fdata-sections -ffunction-sections
# インクルードパスを指定
CFLAGS += $(addprefix -I,$(INCLUDE_DIRS))
# リンカー向けのオプション
LDFLAGS += -Wl,-Map=$(TARGET_MAP) -Wl,--cref -Wl,-gc-sections -Wl,--print-memory-usage
# OS環境ではなくスタンドアロンを指定
LDFLAGS += -lgcc -lm -lnosys -nostartfiles
# リンカースクリプトなどを指定
LDFLAGS += --specs=nosys.specs --specs=nano.specs -Wl,-T,$(LINKER_SCRIPT)
# 中間生成ファイル
OBJS := $(STARTUP_SRC:.S=.o) $(APP_SRCS:.c=.o) $(SDK_SRCS:.c=.o)
.PHONY: all
all: $(TARGET_BIN)
$(TARGET_ELF): $(TARGET_ELF:.elf=.o) $(OBJS)
$(CC) $(CFLAGS) $(LDFLAGS) $^ -o $@
$(TARGET_BIN): $(TARGET_ELF)
$(OBJCOPY) -O binary $< $@
%.o: %.c
$(CC) $(CFLAGS) -c $< -o $@
%.o: %.S
$(CC) $(CFLAGS) -c $< -o $@
.PHONY: clean
clean:
$(RM) $(TARGET_ELF) $(TARGET_BIN) $(TARGET_MAP) $(OBJS) $(TARGET_ELF:.elf=.o)
ビルド
事前に riscv-none-elf-gcc などを準備し、パスを通しておいてください。
(たとえば https://github.com/xpack-dev-tools/gcc-xpack など)
git clone https://github.com/verylowfreq/sdk_example_ch32v203/
cd sdk_example_ch32v203
git submodule update --init
make