PREFIX = /usr/local ARCH = arm-none-eabi BINDIR = $(PREFIX)/$(ARCH)/bin ADDNAME = $(ARCH)- AR = $(BINDIR)/$(ADDNAME)ar AS = $(BINDIR)/$(ADDNAME)as CC = $(BINDIR)/$(ADDNAME)gcc LD = $(BINDIR)/$(ADDNAME)ld NM = $(BINDIR)/$(ADDNAME)nm OBJCOPY = $(BINDIR)/$(ADDNAME)objcopy OBJDUMP = $(BINDIR)/$(ADDNAME)objdump RANLIB = $(BINDIR)/$(ADDNAME)ranlib STRIP = $(BINDIR)/$(ADDNAME)strip OBJS += reset.o main.o OBJS += vector.o TARGET = xiao CFLAGS = -Wall -mcpu=cortex-m0 -mthumb -nostdinc -nostdlib -fno-builtin CFLAGS += -I. #CFLAGS += -g CFLAGS += -Os CFLAGS += -DXIAO CFLAGS += -DCPU_CLOCK=12000000L LFLAGS = -static -T ld.scr -L. .SUFFIXES: .c .o .SUFFIXES: .s .o .SUFFIXES: .S .o all : $(TARGET) $(TARGET) : $(OBJS) $(CC) $(OBJS) -o $(TARGET) $(CFLAGS) $(LFLAGS) cp $(TARGET) $(TARGET).elf $(STRIP) $(TARGET) .c.o : $< $(CC) -c $(CFLAGS) $< .s.o : $< $(CC) -c $(CFLAGS) $< .S.o : $< $(CC) -c $(CFLAGS) $< $(TARGET).mot : $(TARGET) $(OBJCOPY) -O srec $(TARGET) $(TARGET).mot $(TARGET).hex : $(TARGET).mot $(OBJCOPY) -I srec -O ihex $(TARGET).mot $(TARGET).hex image : $(TARGET).hex lpc21isp xiao.hex /dev/ttyUSB0 115200 12000 clean : rm -f $(OBJS) $(TARGET) $(TARGET).elf $(TARGET).mot $(TARGET).hex rm -f *~
第2世代 Xiaoの検討 最低限のソースコード
作成日 | : | 2020/07/12 |
---|---|---|
最終更新日 | : | 2020/07/13 |
第2世代 Xiaoの検討 最低限のソースコード
作成日 | : | 2020/07/12 |
---|---|---|
最終更新日 | : | 2020/07/13 |
概要
第2世代 Xiaoは第1世代のXiaoとの互換性は考えない予定です。 しかしながら、再利用できる部分は使いたいので一旦main関数を呼び出すところまで簡略化します。
開発環境
開発環境はGNUツールチェーンを使用します。GNU makeを使ってビルドを自動化します。
ソースコード
リンカスクリプトはXiaoのものをとりあえずそのまま利用します。リンカスクリプトのファイル名は12ステップ本を踏襲します。
OUTPUT_FORMAT("elf32-littlearm") OUTPUT_ARCH(arm) MEMORY { romall(rx) : o = 0x00000000, l = 0x00008000 /* 16KB */ romvector(r) : o = 0x00000000, l = 0x00000200 /* top of ROM */ rom(rx) : o = 0x00000200, l = 0x00007e00 ramall(rwx) : o = 0x10000000, l = 0x00001000 /* 4KB */ data(rw) : o = 0x10000000, l = 0x00000800 /* 2KB */ userstack(rw) : o = 0x10000800, l = 0x00000400 /* 1KB */ stack(rw) : o = 0x10000C00, l = 0x00000400 /* end of RAM */ } SECTIONS { .romvector : { _romvector_start = . ; *(.vector) . = ALIGN(4); _romvector_end = . ; } > romvector .text : { _text_start = . ; *(.text) _etext = . ; } > rom .rodata : { _rodata_start = . ; *(.strings) *(.rodata) *(.rodata.*) _erodata = . ; } > rom _data_org = . ; .data : { _data_start = . ; *(.data) . = ALIGN(4); _data_end = . ; _edata = . ; } > data AT> rom .bss : { _bss_start = . ; *(.bss) *(COMMON) . = ALIGN(4); _bss_end = . ; _ebss = . ; } > data AT> rom . = ALIGN(4); _end = . ; .freearea : { _freearea = . ; } > data .userstack : { _userstack = . ; } > userstack .stack : { _process_stack = . + 0x0100; _main_stack = . + 0x0200; } > stack }
必要な定義は一旦defines.hにまとめます。追々ファイルを整理していきます。
/** defines.h Copyright (c) 2013-2020 Akihisa ONODA This software is released under the MIT License. http://opensource.org/licenses/mit-license.php */ #ifndef __DEFINES_H__ #define __DEFINES_H__ #define NULL ((void *)0) #define SYSMEMREMAP ((volatile unsigned long *)0x40048000) #define SYSAHBCLKCTRL ((volatile unsigned long *)0x40048080) #define AHB_IOCON (1 << 16) #endif /* __DEFINES_H__ */
電源投入された時、一番初めにvector.cに定義したvectorの0番目にスタックポインタのアドレスを定義し、1番目のアドレスに飛びます。ここでアドレスに+1しているのはARM Cortex-M0の仕様です。ブートストラップ処理を書いていきます。LPC1114FN28/102はRAMが4 kbyteと少ないので第1世代のXiao同様にブートローダは実装せずに直接ブートする仕様にします。
/** vecter.c Copyright (c) 2013-2020 Akihisa ONODA This software is released under the MIT License. http://opensource.org/licenses/mit-license.php */ extern unsigned long _main_stack[]; void reset_entry(void); const void *vector[] __attribute__ ((section(".romvector"))) = { _main_stack, // MSP reset_entry + 1, // 1: Reset reset_entry + 1, // 2: NMI reset_entry + 1, // 3: HardFault reset_entry + 1, // 4: reserved reset_entry + 1, // 5: reserved reset_entry + 1, // 6: reserved reset_entry + 1, // 7: reserved reset_entry + 1, // 8: reserved reset_entry + 1, // 9: reserved reset_entry + 1, // 10: reserved reset_entry + 1, // 11: SVC reset_entry + 1, // 12: reserved reset_entry + 1, // 13: reserved reset_entry + 1, // 14: PendSV reset_entry + 1, // 15: SysTick reset_entry + 1, // 16: External Interrupt PIO0_0 reset_entry + 1, // 17: External Interrupt PIO0_1 reset_entry + 1, // 18: External Interrupt PIO0_2 reset_entry + 1, // 19: External Interrupt PIO0_3 reset_entry + 1, // 20: External Interrupt PIO0_4 reset_entry + 1, // 21: External Interrupt PIO0_5 reset_entry + 1, // 22: External Interrupt PIO0_6 reset_entry + 1, // 23: External Interrupt PIO0_7 reset_entry + 1, // 24: External Interrupt PIO0_8 reset_entry + 1, // 25: External Interrupt PIO0_9 reset_entry + 1, // 26: External Interrupt PIO0_10 reset_entry + 1, // 27: External Interrupt PIO0_11 reset_entry + 1, // 28: External Interrupt PIO1_10 reset_entry + 1, // 29: External Interrupt C_CAN reset_entry + 1, // 30: External Interrupt SPC/SSP1 reset_entry + 1, // 31: External Interrupt I2C0 reset_entry + 1, // 32: External Interrupt reset_entry + 1, // 33: External Interrupt reset_entry + 1, // 34: External Interrupt reset_entry + 1, // 35: External Interrupt reset_entry + 1, // 36: External Interrupt reset_entry + 1, // 37: External Interrupt reset_entry + 1, // 38: External Interrupt reset_entry + 1, // 39: External Interrupt reset_entry + 1, // 40: External Interrupt reset_entry + 1, // 41: External Interrupt reset_entry + 1, // 42: External Interrupt reset_entry + 1, // 43: External Interrupt reset_entry + 1, // 44: External Interrupt reset_entry + 1, // 45: External Interrupt reset_entry + 1, // 46: External Interrupt reset_entry + 1, // 47: External Interrupt reset_entry + 1, // 48: External Interrupt reset_entry + 1, // 49: External Interrupt reset_entry + 1, // 50: External Interrupt reset_entry + 1, // 51: External Interrupt reset_entry + 1, // 52: External Interrupt reset_entry + 1, // 53: External Interrupt reset_entry + 1, // 54: External Interrupt reset_entry + 1, // 55: External Interrupt reset_entry + 1, // 56: External Interrupt reset_entry + 1, // 57: External Interrupt reset_entry + 1, // 58: External Interrupt reset_entry + 1, // 59: External Interrupt reset_entry + 1, // 60: External Interrupt reset_entry + 1, // 61: External Interrupt reset_entry + 1, // 62: External Interrupt reset_entry + 1, // 63: External Interrupt };
今回は、reset_entryに飛ぶようにしているので、reset.cに定義されたreset_entry()が呼び出されます。アセンブラはインラインアセンブラでできるだけ記述するようにし、*.cファイルで済むようにします。
/** reset.c Copyright (c) 2013-2020 Akihisa ONODA This software is released under the MIT License. http://opensource.org/licenses/mit-license.php */ #include "defines.h" __attribute__ ((section(".text.startup"))) void reset_entry(void) { extern volatile char _data_org[], _data_start[], _data_end[]; extern volatile char _bss_start[], _bss_end[]; volatile char *s, *d; asm("ldr r0, =_process_stack\n" "msr psp, r0\n"); asm("mov r0, #2\n" "msr control, r0\n"); asm("memmap_init:\n"); *SYSMEMREMAP = 2; asm("clock_init:\n"); *SYSAHBCLKCTRL |= AHB_IOCON; for(d = _data_start, s = _data_org; d < _data_end; *d++ = *s++); for(d = _bss_start; d < _bss_end; *d++ = 0); asm("b main\n"); }
reset_entry()の最後でmain.cに定義されたmain()を呼び出してブートストラップが完了します。
/** main.c Copyright (c) 2013-2020 Akihisa ONODA This software is released under the MIT License. http://opensource.org/licenses/mit-license.php */ #include "defines.h" int main(void) { return 0; }