オフラインでGCCを使ったmbed開発環境を作る。(第二版)

mbedって何ぞや?

NXP LPC1768のARMのMPUにブレッドボードで使いやすい足が生えて簡単にファームウェアを焼くことができるUSBクライアントポートがついたお手軽マイコン
ADC/CAN/DAC/イーサネット/DMA/外部割込み/GPIO/I2C/I2S/PWM/RTC/SPI/SSP/UART/WDT/USBホスト/USBクライアントなど機能が盛りだくさん。
ただしハードウエアDSPは持ってません。(乗算除算のみ)
しかし、このmbedはWeb上からコンパイルを行うためにネット環境がなかったりPCのスペックやブラウザのバージョンが低かったりすると色々と問題なのでオフラインでエディタかIDEとmakeで開発したい…。
というときのための私的なメモです。
ちなみにこの開発環境はLPC1769の乗ったLPCXpressoにも対応してたりします。というかまんま上位互換です。

仕様
  • CPU: Cortex-M3(ARMv7-M)
    • *AVRと同じハーバードアーキテクチャ、コードはROM(Flash)でスタックとヒープのみIWRAM(内部メモリ)に展開される。
  • ISA(対応命令): Thumb/Thumb-2
    • *ARM命令は対応せず、Thumb命令で動作
  • 動作電圧: 3.3V
    • *I/Oは5Vトレラント[許容]
    • *ADCは定格3.3Vで12bit, DACは10bit
  • クロック: 100MHz
  • モリー:64kB
  • FlashROM: 512kB

必要なソフトウエア

CMSISって何よ?

Cortex Microcontroller Software Interface Standardの略です。リンカスクリプト、ブートストラップ、ペリフェラル(周辺機能)のドライバライブラリが含まれています。

CMSISから必要なファイルを抽出、そして修正を行う。

  • \lpc17xx.cmsis.driver.library\Core\CM3\CoreSupport から
    • core_cm3.c
    • core_cm3.h
    • core_cmFunc.h
    • core_cmInstr.h
  • \lpc17xx.cmsis.driver.library\Core\CM3\DeviceSupport\NXP\LPC17xx から
    • LPC17xx.h
    • system_LPC17xx.c
    • system_LPC17xx.h
  • \lpc17xx.cmsis.driver.library\Core\CM3\DeviceSupport\NXP\LPC17xx\startup\gcc から
    • startup_LPC17xx.s
  • \lpc17xx.cmsis.driver.library\makesection\makerule\example から
    • ldscript_rom_gnu.ld

以上のファイルをひとつのフォルダに設置してください。

Makefileを作る。

#  Project Name
PROJECT=mbed_test

#  List of the objects files to be compiled/assembled
OBJECTS=startup_LPC17xx.o core_cm3.o system_LPC17xx.o $(PROJECT).o 
LSCRIPT=ldscript_rom_gnu.ld
OPTIMIZATION = s -fno-schedule-insns2 -fsection-anchors -fpromote-loop-indices -ffunction-sections -fdata-sections
#DEBUG = -g

#  Compiler Options
GCFLAGS = -Wall -mcpu=cortex-m3 -mfloat-abi=softfp -mthumb -mfix-cortex-m3-ldrd -O$(OPTIMIZATION) $(DEBUG)
GCFLAGS += -D__RAM_MODE__=0
LDFLAGS = -mcpu=cortex-m3 -mfloat-abi=softfp -mthumb -mfix-cortex-m3-ldrd -O$(OPTIMIZATION) -Wl,-Map=$(PROJECT).map -T$(LSCRIPT)
ASFLAGS = -mcpu=cortex-m3 --defsym RAM_MODE=0

#  Compiler/Assembler/Linker Paths
GCC = arm-none-eabi-gcc
AS = arm-none-eabi-as
LD = arm-none-eabi-ld
OBJCOPY = arm-none-eabi-objcopy
OBJDUMP = arm-none-eabi-objdump
REMOVE = rm -f
SIZE = arm-none-eabi-size

#########################################################################

all:: $(PROJECT).hex $(PROJECT).bin $(PROJECT).lss

$(PROJECT).lss: $(PROJECT).elf
	$(OBJDUMP) -h -S $(PROJECT).elf > $(PROJECT).lss
	
$(PROJECT).bin: $(PROJECT).elf
	$(OBJCOPY) -O binary -j .text -j .data $(PROJECT).elf $(PROJECT).bin

$(PROJECT).hex: $(PROJECT).elf
	$(OBJCOPY) -R .stack -O ihex $(PROJECT).elf $(PROJECT).hex

$(PROJECT).elf: $(OBJECTS)
	$(GCC) $(LDFLAGS) $(OBJECTS) -o $(PROJECT).elf

stats: $(PROJECT).elf
	$(SIZE) $(PROJECT).elf

clean:
	$(REMOVE) $(OBJECTS)
	$(REMOVE) $(PROJECT).bin
	$(REMOVE) $(PROJECT).elf
	$(REMOVE) $(PROJECT).hex
	$(REMOVE) $(PROJECT).lss
	$(REMOVE) $(PROJECT).map

#########################################################################
#  Default rules to compile .c and .cpp file to .o
#  and assemble .s files to .o

.c.o :
	$(GCC) $(GCFLAGS) -c $<

.cpp.o :
	$(GCC) $(GCFLAGS) -c $<

.S.o :
	$(AS) $(ASFLAGS) -o $@ $<

#########################################################################

上記をコピーアンドペーストしてMakefileを作成してください。

最後に

あとはMakefileのPROJECTで指定した名前のソースファイル、ここではmbed_test.cppを作成し、

#include "LPC17xx.h"

volatile unsigned long tick;

extern "C"
{
	void SysTick_Handler(void)
	{
		tick++; // 1ms Tick...
	}
}

int main(void)
{
	SysTick_Config(SystemCoreClock/1000 - 1);
	
	/* ... */
	
	return 0;
}

ではじめることができます。
気を付けなければならないことは拡張子がcppつまり、C++コンパイルした場合において割り込みハンドラはC言語による関数宣言をしておかないと呼出規約のせいかスタックの取り方がちがうのか正常に動作にしません。
あと、ペリフェラルのライブラリは

  • \lpc17xx.cmsis.driver.library\Drivers

にありますので適宜インクルードしてコードをOBJECTSに追加してください。あとはMakeすればコンパイルできるはず。
予断ですが、CodeSourceryのコンパイラのlibcはnewlibを使っているみたいですね。組み込みでまともなstdio.hとstrings.hが手に入るのは強力だと思います。
devkitpro環境を作るために必死でパッチをあてbinutils,gcc,newlibをコンパイルした時代と比べれば楽な世の中になりましたね。
mbed.hなどは

とかでソースがダウンロードはできるもののARM謹製のコンパイラでlibcなどのシステムコールの実装が大きく違っているので流用できません。