こんにちは、しゅうです。前々回と前回までで環境構築やほぼ必要なファイルを用意できました。
いよいよ残すところは、後2つファイルを用意して書き込みを実行する、です。
ということで今回は、main.cとMakefileを用意して、書き込み手順の解説をしていきます。
main.c
今回はLEDを光らせるだけなので、初期化などを含め1つのファイルにまとめます。書き方自体は今までとそこまで変わりません。
まず初めにポートの設定をしておく必要があります。CS+の時はportdef.hで定義していたので、そこからLEDの分をコピーして今回はグローバル変数として定義します。加えて、そのポートを出力に切り替えるためIO_OUT (1)も定義しておきます(これはstatic_parameters.hで定義されていました)。そしてメイン関数に入る前に初期化を行うので、CS+で使っていたinit.cからinit_clockとinit_cmt関数を引っ張ってきます。さらにもう1つ割り込み関数として、LEDのOn/Offをするためのint_cmt関数を用意します。そしてmain関数でポートの設定をしたり初期化の関数を呼び出したりします。
文字で書くとプログラムは以上ですがイメージしづらいと思うので、今回は書き出しちゃいます。
#include "iodefine.h" #define LED3 (PORTA.PODR.BIT.B0) #define LED2 (PORTA.PODR.BIT.B4) #define LED1 (PORTA.PODR.BIT.B6) #define LED0 (PORTB.PODR.BIT.B0) #define IO_OUT (1) void init_clock(void){ SYSTEM.PRCR.WORD = 0xa50b; SYSTEM.PRCR.WORD = 0xa50b; SYSTEM.PLLCR.WORD = 0x0F00; /* PLL 12.000MHz * 16 = 192MHz*/ SYSTEM.PLLWTCR.BYTE = 0x0F; /* 4194304cycle(Default) */ SYSTEM.PLLCR2.BYTE = 0x00; /* PLL ENABLE */ // ICK : 192/2 = 96MHz //CPU DMAC DTC ROM RAM // PCLKA : 192/2 = 96MHz //etc // PCLKB : 192/4 = 48MHz //PCLKB=PCLK SYSTEM.SCKCR.LONG = 0x21C21211; //FCK1/4 ICK1/2 BCLK??~ SDCLK??~ BCK1/4 PCLKA1/2 PCLKB1/4 SYSTEM.SCKCR2.WORD = 0x0032; /* UCLK1/4 IEBCK1/4 */ SYSTEM.BCKCR.BYTE = 0x01; /* BCLK = 1/2 */ SYSTEM.SCKCR3.WORD = 0x0400; } void init_cmt(void){ SYSTEM.PRCR.WORD = 0xA502; MSTP(CMT0) = 0; SYSTEM.PRCR.WORD = 0xA500; CMT0.CMCR.BIT.CKS=1; // PCLK/32 1.5MHz CMT0.CMCR.BIT.CMIE=1; CMT0.CMCNT=0; CMT0.CMCOR=1500-1; //1kHz IEN(CMT0,CMI0) = 1; IPR(CMT0,CMI0) = 15; IR(CMT0,CMI0)=0; CMT.CMSTR0.BIT.STR0=1; } void int_cmt(void){ static short i=0; if(i==1000){ LED3=1; LED0=LED1=LED2=0; }else if(i==2000){ LED2=1; LED0=LED1=LED3=0; }else if(i==3000){ LED1=1; LED0=LED2=LED3=0; }else if(i==4000){ LED0=1; LED1=LED2=LED3=0; i=0; } i++; } int main(void){ init_clock(); PORTA.PDR.BIT.B0 = IO_OUT; //LED3 PORTA.PDR.BIT.B4 = IO_OUT; //LED2 PORTA.PDR.BIT.B6 = IO_OUT; //LED1 PORTB.PDR.BIT.B0 = IO_OUT; //LED0 init_cmt(); while(1){ } return 0; }
これでmain関数は出来上がりです。次はmakefileを作っていきます。
makefile
makefileの書き方は基本的に
作りたいファイル:入力するファイル
-TAB-作り方
という構造になります。CS+の時はボタン1つで書き込むための.motファイルを生成してくれましたが、今回は上の構造を使いながら1個ずつ記載していく感じになります。ちなみに基本的に上から順番に実行が行われますが、既にmakeを実行して「作りたいファイル」が既にある場合、「入力するファイル」の最終更新日が「作りたいファイル」よりも後だった時のみ実行されるようになります。なかなか賢いですね。
基本構造以外には作り方や入力ファイルがないような構造もあります。よくみる、ビルドしたものを一旦消すコマンドのmake cleanなんかは次のように記述されています。
clean: -TAB-rm -rf <makeしたときに生成されたファイルやディレクトリ>
ここでは、入力するファイルが指定されていないのでそのまま作り方、すなわちコマンドの部分が実行されます。
後は、初めにmakeでビルドしたいファイルやビルドに用いるライブラリなどを指定していきます。今回は次のようにかけます(詳しいことはmakefileの書き方!などの記事を参照してください)。
TARGET = PiCoClassic3 DEVICE = R5F5631M BUILD = build VPATH = ../ ASOURCES = start.s CSOURCES = main.c \ intprg.c \ vecttbl.c LDSCRIPT = $(DEVICE).ld USER_DEFS = SIG_RX631 F_ICLK=96000000 F_PCLKA=96000000 F_PCLKB=48000000 F_FCLK=48000000 F_BCLK=96000000 WRITER = rx_prog INC_APP = . ../ include OPTIMIZE = -O0 CP_OPT = -Wall -Werror \ -Wno-unused-variable \ -Wno-unused-function \ -fno-exceptions \ -fno-rtti CC_OPT = -Wall -Werror \ -Wno-unused-variable \ -fno-exceptions SYSINCS = $(addprefix -I, $(INC_SYS)) APPINCS = $(addprefix -I, $(INC_APP)) AINCS = $(SYSINCS) $(APPINCS) CINCS = $(SYSINCS) $(APPINCS) PINCS = $(SYSINCS) $(APPINCS) LIBINCS = $(addprefix -L, $(LIB_ROOT)) DEFS = $(addprefix -D, $(USER_DEFS)) LIBS = $(addprefix -l, $(USER_LIBS)) #You should not have to change anything here AS = rx-elf-as CC = rx-elf-gcc CP = rx-elf-g++ AR = rx-elf-ar LD = rx-elf-ld OBJCOPY = rx-elf-objcopy OBJDUMP = rx-elf-objdump SIZE = rx-elf-size ALL_ASFLAGS = $(AFLAGS) $(MCU_TARGET) $(DEFS) CFLAGS = -std=gnu99 $(CC_OPT) $(OPTIMIZE) $(MCU_TARGET) $(DEFS) PFLAGS = -std=c++14 $(CP_OPT) $(OPTIMIZE) $(MCU_TARGET) $(DEFS) override LDFLAGS = $(MCU_TARGET) -nostartfiles -Wl, -Map, $(TARGET).map -T $(LDSCRIPT) OBJCOPY_OPT = --srec-forceS3 --srec-len 32 OBJECTS = $(addprefix $(BUILD)/,$(patsubst %.s,%.o,$(ASOURCES))) \ $(addprefix $(BUILD)/,$(patsubst %.c,%.o,$(CSOURCES))) \ $(addprefix $(BUILD)/,$(patsubst %.cpp,%.o,$(PSOURCES))) DEPENDS = $(patsubst %.o,%.d, $(OBJECTS)) .PHONY: all clean .SUFFIXES: .rc .hpp .h .s .c .cpp .o all: $(BUILD) $(TARGET).elf text $(TARGET).elf: $(OBJECTS) $(LDSCRIPT) Makefile $(CC) $(LDFLAGS) $(LIBINCS) -o $@ $(OBJECTS) $(LIBS) $(SIZE) $@ $(BUILD)/%.o: %.s mkdir -p $(dir $@); \ $(AS) -c $(AOPT) $(AFLAGS) $(AINCS) -o $@ $< $(BUILD)/%.o: %.c mkdir -p $(dir $@); \ $(CC) -c $(COPT) $(CFLAGS) $(CINCS) $(CCWARN) -o $@ $< $(BUILD)/%.o: %.cpp mkdir -p $(dir $@); \ $(CP) -c $(POPT) $(PFLAGS) $(PINCS) $(CPWARN) -o $@ $< $(BUILD)/%.d: %.cpp mkdir -p $(dir $@); \ $(CC) -MM -DDEPEND_ESCAPE $(COPT) $(CFLAGS) $(APPINCS) $< \ | sed 's/$(notdir $*)\.o:/$(subst /,\/,$(patsubst %.d,%.o,$@) $@):/' > $@ ; \ [ -s $@ ] || rm -f $@ $(BUILD)/%.d: %.cpp mkdir -p $(dir $@); \ $(CP) -MM -DDEPEND_ESCAPE $(POPT) $(PFLAGS) $(APPINCS) $< \ | sed 's/$(notdir $*)\.o:/$(subst /,\/,$(patsubst %.d,%.o,$@) $@):/' > $@ ; \ [ -s $@ ] || rm -f $@ text: mot lst bin: $(TARGET).bin mot: $(TARGET).mot lst: $(TARGET).lst %.lst: %.elf $(OBJDUMP) -h -S $< > $@ %.mot: %.elf $(OBJCOPY) $(OBJCOPY_OPT) -O srec $< $@ %.bin: %.elf $(OBJCOPY) -O binary $< $@ clean: rm -rf $(BUILD) $(TARGET).elf $(TARGET).mot $(TARGET).lst $(TARGET).map
保存したら、あとはmakeを実行するだけで.motファイルなどが生成されます。残すはPi:Coに書き込むだけです!
書き込み
ハードウェア側の書き込み手順はCS+の時と同じです。CPUボードのモードスイッチをFWの方に切り替えてから電源を入れて、こちらの記事でご紹介したようにパソコンとUSB-serialモジュールとPi:Coを接続しましょう。次はソフト側に移ります。
ターミナルで、makeをしたディレクトリにいるようにしましょう(.motファイルが生成されたところです。)。そこでこちらの記事でご紹介したrx_progを使います。次のように実行しましょう。僕の場合、は/dev/tty.usbserial-DM01OYUOです。
$ rx_prog --verbose --progress --port= --speed=57600 --device=RX631 --write PiCoClassic3.mot
これで書き込みができる!と思ったらエラーが返って来ちゃいました。
でも安心してください、CPUボードのリセットボタンを押してからもう一度実行して見てください。すると、Connection OK.と表示されて書き込みが始まります。次のように表示されて再度コマンドが打てるようになれば完了です。
それでは、Pi:Coの電源を切って、CPUボードのモードスイッチをRUNに切り替えてからもう一度電源を入れると、LEDが順番に光ります。
まとめ
長い道のりでしたが、これでMacからでも開発ができるようになりました!早速、今までのプログラムを盛り込んでmakeして見たりしたのですが、まだ不具合がちらほらあるみたいです。
迷路解析までは、もう少し時間がかかりそうです・・・でも無事できるようになったらまた情報をまとめたり、コードなどを公開していきたいなって考えています♪