また,H8マイコンへのバイナリーデータ転送の面倒な処理もmakeでできる.このよ うにすることにより,諸君の作業は格段に楽になる.
この実験で使うMakefileには,次の機能がある.
1 TARGET = h8exp.mot 2 3 CFLAGS = -O -mh -g -mrelax -mint32 -DH8_3664 4 TOOL_PREFIX = h8300-hms- 5 CC = $(TOOL_PREFIX)gcc 6 7 LDSCRIPT = h8_link.x 8 CRT0 = h8_start.s 9 SRCS = experiment.c 10 FUNC = h8c.c 11 12 all : $(TARGET) 13 14 $(TARGET): $(TARGET:.mot=.exe) 15 $(TOOL_PREFIX)objcopy -O srec $(TARGET:.mot=.exe) $@ 16 17 $(TARGET:.mot=.exe): Makefile $(LDSCRIPT) $(SRCS:.c=.o) $(FUNC:.c=.o) \ 18 $(CRT0) $(LIBS) 19 $(CC) $(CFLAGS) -T $(LDSCRIPT) -nostdlib $(CRT0) \ 20 $(SRCS:.c=.o) $(FUNC:.c=.o) -o $@ $(LIBS) -lc -lgcc 21 22 write: 23 h8write -3664 $(TARGET) /dev/ttyS0 24 25 clean : 26 rm -f $(TARGET) 27 rm -f $(TARGET:.mot=.exe) 28 rm -f $(SRCS:.c=.o) 29 rm -f $(FUNC:.c=.o)
に示したリスト
1を変えることによりできる.しかし,ライントレーサーを制御
を司るH8マイコンのプログラムは,リスト1のみでできているわ
けではない.これから示すさまざまなプログラムからできあがっている.
1 #ifndef H8C_H
2 #define H8C_H
3
4 #define _nop() asm volatile ("nop");
5
6 void init_led(void);
7 void init_pwm(void);
8 void start_pwm(void);
9 void duty_pwm(unsigned int b, unsigned int d);
10 void ADC_init(void);
11 void ADC(void);
12
13 typedef union{
14 unsigned char BYTE;
15 struct{
16 unsigned char ADF:1;
17 unsigned char ADIE:1;
18 unsigned char ADST:1;
19 unsigned char SCAN:1;
20 unsigned char CKS:1;
21 unsigned char CH2:1;
22 unsigned char CH1:1;
23 unsigned char CH0:1;
24 }BIT;
25 }set_ADC;
26
27 int ch1, ch2, ch3, ch4;
28
29 #endif
1 #include "h8_3664.h"
2 #include "h8c.h"
3
4
5 //============================================================
6 // LED点灯のための初期化関数
7 // Port5を使うときに最初,1回だけに呼び出す
8 // PDR5のビットの設定で,点灯するLEDを決める
9 //============================================================
10 void init_led(void){
11 PMR5 &= 0xc0; // Port Mode Register 5 の設定
12 // 0:汎用入出力 1:マニュアルを見よ
13 PCR5 |= 0x3f; // Port Control Register 5の設定
14 // 0:入力 1:出力 */
15 PDR5 &= 0xc0; // Port Data Register
16 }
17
18
19 //============================================================
20 // PWMを使うための初期化関数
21 // PWMを使うときに,最初1回呼び出す
22 //============================================================
23 void init_pwm(void){
24 TMRW |= 0x05; /* FTIOBとFTIOD端子をPWM出力に */
25
26 TCRW |= 0x80; /* コンペアマッチAによりカウンタクリアー */
27 TCRW |= 0x30; /* クロックセレクト 内部クロック phi/8 (=2MHz)*/
28 TCRW |= 0x0a; /* タイマ出力セットレベル コンペアマッチまで1 */
29
30 TCNT = 0x0000; /* カウンタ16ビットの初期値 */
31
32 GRA = 0xffff;
33
34 }
35
36
37 //============================================================
38 // PWMのDutyを決める
39 // 第一引数:FTIOB 第二引数:FTIOD
40 //============================================================
41 void duty_pwm(unsigned int b, unsigned int d){ // pwm デューティ [%]
42
43 GRB = (unsigned int)655*b;
44 GRD = (unsigned int)655*d;
45
46 }
47
48
49 //============================================================
50 // PWMのスタート時に呼び出す
51 //============================================================
52 void start_pwm(void){
53 TMRW |= 0x80; /* カウンタースタート */
54 }
55
56
57 //============================================================
58 // AD変換器の初期化関数
59 //============================================================
60 void init_ADC(void)
61 {
62
63 set_ADC *set;
64
65 set=(set_ADC *)&ADCSR;
66
67 set->BIT.ADF=0;
68 set->BIT.ADIE=0;
69 set->BIT.ADST=0;
70 set->BIT.SCAN=1;
71 set->BIT.CKS=0;
72 set->BIT.CH2=0;
73 set->BIT.CH1=1;
74 set->BIT.CH0=1;
75
76 }
77
78 //============================================================
79 // AD変換器を行い結果を設定
80 // ch1:AN0の結果 0:白 1:黒
81 // ch2:AN1の結果 0:白 1:黒
82 // ch3:AN2の結果 0:白 1:黒
83 // ch4:AN3の結果 0:白 1:黒
84 //============================================================
85 void ADC(void)
86 {
87
88 ADCSR &=0x7f; // ADF=0 AD完了フラグをゼロに
89 ADCSR |= 0x20; // ADST=1 ADCスタート
90
91 while(!(ADCSR & 0x80)); // AD変換完了まで待つ
92 ADCSR &= 0xdf; // ADST=0 ADC stop
93
94 ch1=(unsigned int)(ADDRA >> 6)<200 ? 1:0;
95 ch2=(unsigned int)(ADDRB >> 6)<200 ? 1:0;
96 ch3=(unsigned int)(ADDRC >> 6)<200 ? 1:0;
97 ch4=(unsigned int)(ADDRD >> 6)<200 ? 1:0;
98
99 }
3-5行目がアセンブラで命令を記述している.マクロ名を指定することにで,アセンブラ の命令が実行される.簡単なアセンブラの命令を実行するときに便利である.
14-96行目でレジスターのアドレスを定義している.レジスター名--ここではマクロ名 になるが--とそれに対応するアドレスは,H8のマニュアルに書いてある.このようにす ると,無味乾燥な16進数のアドレスが意味のある名前に置き換えることができる.プログ ラムが書きやすくなる.コンパイル時にgccのプリプロセッサーがこのマクロ名を対応す る16進数に変換する.
レジスターとアドレスの関係は,ルネサステクノロジー社の「H8/3664グループハードウェ
アーマニュアル」 [3]に詳しく書かれている.
1 #ifndef H8_3664_H
2 #define H8_3664_H
3 #define STI() asm volatile ("andc.b #0x7f,ccr")
4 #define CLI() asm volatile ("orc.b #0x80,ccr")
5 #define SLEEP() asm volatile ("sleep")
6
7 #define VOLATILE_BYTE(addr) (*(volatile unsigned char*)(addr))
8 #define VOLATILE_WORD(addr) (*(volatile unsigned short*)(addr))
9
10 //======================================================================
11 // Definitions of H8/3664 Internal Registers
12 // DO NOT EDIT!
13 //======================================================================
14 #define TMRW VOLATILE_BYTE(0xff80)
15 #define TCRW VOLATILE_BYTE(0xff81)
16 #define TIERW VOLATILE_BYTE(0xff82)
17 #define TSRW VOLATILE_BYTE(0xff83)
18 #define TIOR0 VOLATILE_BYTE(0xff84)
19 #define TIOR1 VOLATILE_BYTE(0xff85)
20
21 #define TCNT VOLATILE_WORD(0xff86)
22 #define GRA VOLATILE_WORD(0xff88)
23 #define GRB VOLATILE_WORD(0xff8a)
24 #define GRC VOLATILE_WORD(0xff8c)
25 #define GRD VOLATILE_WORD(0xff8e)
26
27 #define FLMCR1 VOLATILE_BYTE(0xff90)
28 #define FLMCR2 VOLATILE_BYTE(0xff91)
29 #define FLPWCR VOLATILE_BYTE(0xff92)
30 #define EBR1 VOLATILE_BYTE(0xff93)
31 #define FENR VOLATILE_BYTE(0xff9b)
32 #define TCRV0 VOLATILE_BYTE(0xffa0)
33 #define TCSRV VOLATILE_BYTE(0xffa1)
34 #define TCORA VOLATILE_BYTE(0xffa2)
35 #define TCORB VOLATILE_BYTE(0xffa3)
36 #define TCNTV VOLATILE_BYTE(0xffa4)
37 #define TCRV1 VOLATILE_BYTE(0xffa5)
38 #define TMA VOLATILE_BYTE(0xffa6)
39 #define TCA VOLATILE_BYTE(0xffa7)
40 #define SMR VOLATILE_BYTE(0xffa8)
41 #define BRR VOLATILE_BYTE(0xffa9)
42 #define SCR3 VOLATILE_BYTE(0xffaa)
43 #define TDR VOLATILE_BYTE(0xffab)
44
45 #define SSR VOLATILE_BYTE(0xffac)
46 #define RDR VOLATILE_BYTE(0xffad)
47
48 #define ADDRA VOLATILE_WORD(0xffb0)
49 #define ADDRB VOLATILE_WORD(0xffb2)
50 #define ADDRC VOLATILE_WORD(0xffb4)
51 #define ADDRD VOLATILE_WORD(0xffb6)
52 #define ADCSR VOLATILE_BYTE(0xffb8)
53 #define ADCR VOLATILE_BYTE(0xffb9)
54
55 #define TCSRWD VOLATILE_BYTE(0xffc0)
56 #define TCWD VOLATILE_BYTE(0xffc1)
57 #define TMWD VOLATILE_BYTE(0xffc2)
58 #define ICCR VOLATILE_BYTE(0xffc4)
59 #define ICSR VOLATILE_BYTE(0xffc5)
60 #define ICDR VOLATILE_BYTE(0xffc6)
61 #define SARX VOLATILE_BYTE(0xffc6)
62 #define ICMR VOLATILE_BYTE(0xffc7)
63 #define SAR VOLATILE_BYTE(0xffc7)
64 #define ABRKCR VOLATILE_BYTE(0xffc8)
65 #define ABRKSR VOLATILE_BYTE(0xffc9)
66 #define BARH VOLATILE_BYTE(0xffca)
67 #define BARL VOLATILE_BYTE(0xffcb)
68 #define BDRH VOLATILE_BYTE(0xffcc)
69 #define BDRL VOLATILE_BYTE(0xffcd)
70 #define PUCR1 VOLATILE_BYTE(0xffd0)
71 #define PUCR5 VOLATILE_BYTE(0xffd1)
72 #define PDR1 VOLATILE_BYTE(0xffd4)
73 #define PDR2 VOLATILE_BYTE(0xffd5)
74 #define PDR5 VOLATILE_BYTE(0xffd8)
75 #define PDR7 VOLATILE_BYTE(0xffda)
76 #define PDR8 VOLATILE_BYTE(0xffdb)
77 #define PDRB VOLATILE_BYTE(0xffdd)
78
79 #define PMR1 VOLATILE_BYTE(0xffe0)
80 #define PMR5 VOLATILE_BYTE(0xffe1)
81 #define PCR1 VOLATILE_BYTE(0xffe4)
82 #define PCR2 VOLATILE_BYTE(0xffe5)
83 #define PCR5 VOLATILE_BYTE(0xffe8)
84 #define PCR7 VOLATILE_BYTE(0xffea)
85 #define PCR8 VOLATILE_BYTE(0xffeb)
86 #define SYSCR1 VOLATILE_BYTE(0xfff0)
87 #define SYSCR2 VOLATILE_BYTE(0xfff1)
88 #define IEGR1 VOLATILE_BYTE(0xfff2)
89 #define IEGR2 VOLATILE_BYTE(0xfff3)
90 #define IENR1 VOLATILE_BYTE(0xfff4)
91 #define IRR1 VOLATILE_BYTE(0xfff6)
92 #define IWPR VOLATILE_BYTE(0xfff8)
93 #define MSTCR1 VOLATILE_BYTE(0xfff9)
94 #define TSCR VOLATILE_BYTE(0xfffc)
95
96 #define EKR VOLATILE_BYTE(0xff10)
97
98 #endif
このスタートアップルーチンでは,まずはスタックポインターを設定している.リンカー スクリプトで設定されたスタック領域の先頭アドレス(_stack)をスタックポインター (sp)に設定している.次にROM 領域のデータをRAM領域に転送している.このように することにより,初期値がある変数に対応している.その後,リスト 1をmain関数に実行を移している.実際にはこのメイン関数 は機械語に翻訳され,ラベルは_mainとなる.ここでは,jsrでジャンプして いる.この_mainから戻るようなことがあると,無限ループに入るようにしている.
1 ;; H8/3664 Startup routine 2 3 .h8300h 4 .section .text 5 .global _start 6 _start: 7 mov.l #_stack,sp ;; スタックポインターの設定 8 9 ;; ROM領域のデータをRAMへ転送 10 11 mov.l #___dtors_end,er0 ;; .dtorsの終わりのアドレス 12 mov.l #___data,er1 ;; .dataの開始アドレス 13 mov.l #_edata,er2 ;; .dataの終わりのアドレス 14 ram_data: 15 mov.w @er0,r3 16 mov.w r3,@er1 17 adds #2,er0 18 adds #2,er1 19 cmp.l er2,er1 20 blo ram_data 21 22 ;; main関数の実行 23 24 jsr @_main 25 sleep: 26 sleep 27 bra sleep 28 29 .end
1 OUTPUT_FORMAT("coff-h8300")
2 OUTPUT_ARCH(h8300h)
3 ENTRY("_start")
4 MEMORY
5 {
6 vectors : o = 0x0000, l = 0x0034
7 rom : o = 0x0034, l = 0x7fcc
8 ram : o = 0xf780, l = 0x0400
9 stack : o = 0xff80, l = 0x0000
10 }
11
12 SECTIONS
13 {
14 .vectors : {
15 SHORT(ABSOLUTE(_start))
16 SHORT(ABSOLUTE(_start))
17 SHORT(ABSOLUTE(_start))
18 SHORT(ABSOLUTE(_start))
19 SHORT(ABSOLUTE(_start))
20 SHORT(ABSOLUTE(_start))
21 SHORT(ABSOLUTE(_start))
22 SHORT(DEFINED(_int_nmi)?ABSOLUTE(_int_nmi):ABSOLUTE(_start))
23 SHORT(DEFINED(_int_trap0)?ABSOLUTE(_int_trap0):ABSOLUTE(_start))
24 SHORT(DEFINED(_int_trap1)?ABSOLUTE(_int_trap1):ABSOLUTE(_start))
25 SHORT(DEFINED(_int_trap2)?ABSOLUTE(_int_trap2):ABSOLUTE(_start))
26 SHORT(DEFINED(_int_trap3)?ABSOLUTE(_int_trap3):ABSOLUTE(_start))
27 SHORT(DEFINED(_int_break)?ABSOLUTE(_int_break):ABSOLUTE(_start))
28 SHORT(DEFINED(_int_sleep)?ABSOLUTE(_int_sleep):ABSOLUTE(_start))
29 SHORT(DEFINED(_int_irq0)?ABSOLUTE(_int_irq0):ABSOLUTE(_start))
30 SHORT(DEFINED(_int_irq1)?ABSOLUTE(_int_irq1):ABSOLUTE(_start))
31 SHORT(DEFINED(_int_irq2)?ABSOLUTE(_int_irq2):ABSOLUTE(_start))
32 SHORT(DEFINED(_int_irq3)?ABSOLUTE(_int_irq3):ABSOLUTE(_start))
33 SHORT(DEFINED(_int_wkp)?ABSOLUTE(_int_wkp):ABSOLUTE(_start))
34 SHORT(DEFINED(_int_timera)?ABSOLUTE(_int_timera):ABSOLUTE(_start))
35 SHORT(ABSOLUTE(_start))
36 SHORT(DEFINED(_int_timerw)?ABSOLUTE(_int_timerw):ABSOLUTE(_start))
37 SHORT(DEFINED(_int_timerv)?ABSOLUTE(_int_timerv):ABSOLUTE(_start))
38 SHORT(DEFINED(_int_sci3)?ABSOLUTE(_int_sci3):ABSOLUTE(_start))
39 SHORT(DEFINED(_int_iic)?ABSOLUTE(_int_iic):ABSOLUTE(_start))
40 SHORT(DEFINED(_int_adi)?ABSOLUTE(_int_adi):ABSOLUTE(_start))
41 } > vectors
42
43 .text 0x0034 : {
44 *(.text)
45 *(.strings)
46 *(.rodata)
47 _etext = . ;
48 } > rom
49
50 .tors : {
51 ___ctors = . ;
52 *(.ctors)
53 ___ctors_end = . ;
54 ___dtors = . ;
55 *(.dtors)
56 ___dtors_end = . ;
57 } > rom
58
59 .data : AT ( ADDR(.tors) + SIZEOF(.tors) ){
60 ___data = . ;
61 *(.data)
62 *(.tiny)
63 _edata = .;
64 } > rom
65
66 .bss : AT ( LOADADDR(.data) + SIZEOF(.data) ) {
67 _bss_start = . ;
68 *(.bss)
69 *(COMMON)
70 _end = . ;
71 } >ram
72
73 .stack : {
74 _stack = . ;
75 *(.stack)
76 } > stack
77
78 .stab 0 (NOLOAD) : {
79 [ .stab ]
80 }
81
82 .stabstr 0 (NOLOAD) : {
83 [ .stabstr ]
84 }
85 }