SNSへはこちら

NimでLチカ on STM32 (1)

タイトルの通り、C言語へコンパイルをする Nim といふ言語をやってみました。基本的にマイコンはC言語で書くんだから Nim でもできるやろ(鼻ホジ)ということでやってみました。

やったこと

構造体も含めてほぼ全て Nim で書きたいなあと思いました。ですので、スタートアップルーチン意外は全て Nim で書きました。
基本的に Nim のオンラインマニュアルと、tattaka さんのブログ記事を存分に参考にしました。ありがとうございます。

この記事はstm32 Advent Calendar 2017の7日目の投稿です.間に合ったぜ. 動機 わたしの近況なのですが,最近はマウスのモチベが下がって研究室配属などがあり,マイコンプログラミングから離れてPythonばかり書いています.なので久しぶりにCを書こうとするととても辛い.そこでCの資産が使えて書きやす...

また、STM32F303K8T6 で実際に動作をさせました。本記事では RCCSysTickGPIOA の設定をレジスタ直打ちでとりあえず出来る所までやるということを目標にします。

プロジェクトの作成

Makefile

何らかのプロジェクトディレクトリを作成し、そこのルートに以下の Makefile をおいてください。

CC=arm-none-eabi-gcc
SIZE=arm-none-eabi-size
CFLAGS= -mcpu=cortex-m4 -mthumb -mfloat-abi=hard -mfpu=fpv4-sp-d16 -ffunction-sections -fdata-sections -Os -g
OBJS=$(notdir $(subst .c,.o,$(wildcard src/*.c)) $(subst .c,.o,$(wildcard src/nimcache/*.c)) $(subst .s,.o,$(wildcard src/*.s)))

all: output.elf
    $(SIZE) $^

output.elf: $(OBJS)
    $(CC) $(CFLAGS) -Wl,-T,LinkerScript.ld,-Map=output.map,--gc-sections -o $@ $^

%.o: src/%.c
    $(CC) $(CFLAGS) -c -o $@ $^
%.o: src/nimcache/%.c
    $(CC) $(CFLAGS) -c -o $@ $^
%.o: src/%.s
    $(CC) $(CFLAGS) -c -o $@ $^

flash:
    echo output.elf | xargs -I {} openocd -f interface/cmsis-dap.cfg -f target/stm32f3x.cfg -c 'init;program {};reset;exit'

clean:
    $(RM) *.o *.elf *.map

リンカスクリプト

後は空気読んでやってよ IDE や CubeMX 等で作成したプロジェクトからリンカスクリプトをパクり、同じくルートに LinkerScript.ld と言う名で置きます。なお /DISCARD/ の部分は削除しておいてください。

ソースファイル

まずは src というディレクトリを作成し、そこにスタートアップルーチンを .s という拡張子で置いてください。後は上のリンクから tattaka さんのブログ記事に飛び、panicoverride.nimnimbase.h の処理をします。

僕は以下のような Nim のファイルを書きました。文法の理解も結構時間かかったなあ。main.nim としてくださいね。

Nim の第一引数は外に出してカッコヨク書けるということでイキりました。普通に ms_wait(200) でいいですよ。
コンパイルはこちら。

$ nim cc -c --cpu=arm --d:release --gc:none --os:standalone --deadCodeElim:on src/main.nim

これで nim ファイルがC言語にコンパイルされました。続いて make とすることでバイナリ生成完了です。あとはプログラマで書き込むなり、openocd 使うなりしてください。

知見

  • {.volatile.} は数値への属性ではなく、変数への属性である
    • const は所謂マクロ的な扱いのため、コンパイル時に定数展開される。
  • macro を極めていれば多分もっとコストの低いプログラムが書けた。
    • 現状では GPIOA なら GPIOA のポインタをメモリ上に配置してしまっている。これはもったいない。
    • マクロを使い場合は volatileStore 等を使うことになるが、ちょっと一癖ある。
    • 何らかのプロシージャ内に記述しなければ、なんとグローバルスコープに代入式が記述されるという悲惨な事態に。
  • ms_wait でさり気なくテンプレートを使った。型制約もきれいに出来て良さげである。