AKI-H8/3664用スタートアップルーチン「startup3664.src」
Copyright(C) 10Nov2002
coskx
【1】スタートアップルーチン「startup3664.src」
このスタートアップルーチンはAKI-H8/3664をWindowsマシンでクロスコンパイルして使用している学習者向けのものです。
スタートアップルーチンとは,マイコンの電源ONと同時に起動し,必要な処理を行なって,Cで記述された関数main()をcallするまでの作業を行なうプログラムです。
スタートアップルーチンの役割は
(1)リセットベクトルの設定
(2)割り込みベクトルの設定
(3)スタックポインタの設定
(4)必要なROM領域変数のRAM領域へのコピー
です。
これにマシン語でないと記述できない関数や,割り込み関数のレジスタ退避部をおまけとしてつけます。
(Cで記述できるかどうかはコンパイラに依存します。秋月で販売されているCコンパイラ[評価版Ver2]に対応させてあります。)
AKI-H8/3664のサンプルプログラムで与えられているスタートアップルーチンresetv.marはとても貧弱で,変数が予期せずにROM領域になったりで学習者はとても苦しみます。たとえば
void
func(void)
{
static int
tick=0;
:
tick++;
}
ではtickがROM領域に割り付けられるため,tickは0から変化しません。
この現象に対処するには次のような操作が必要です。
1)初期値はリンカによってROM領域にセットされます。
2)スタートアップルーチンでROMの変数領域をRAMにコピーする。
3)実行ルーチンではRAM側をアクセスする。
この操作を可能にするのはリンカのROMオプションとスタートアップルーチンです。
なおこのstartup3664.srcから作ったstartup3664.objファイルは
「ここ」で取り込んでください。
【2】本スタートアップルーチンの特徴
(1)初期化されたグローバル変数,関数内static変数を,実行時にはRAMに割り当てて
正常に動作させるようにしました。
(2)TimerAのタイマ割り込みの利用をサポートします。
(3)関数main()から戻ってきても,無限ループに入るようにしました。
(4)CPUのコントロールレジスタのCCRでの割り込みマスクビットのセット・リセット関数をCプログラムに提供します。
E_INT()
割り込み許可
D_INT() 割り込み禁止
【3】本スタートアップルーチンを利用した場合のプログラム中での変数の取り扱い
(1)初期化されていないグローバル変数 RAM領域
(2)初期化されたグローバル変数 RAM領域
(3)初期化された関数内static変数 RAM領域
(4)const修飾子のある初期化されたグローバル変数 ROM領域
(5)const修飾子のある初期化された関数内static変数 ROM領域
オート変数はconst修飾語をつけてもスタック領域にセットされ,値の変更をコンパイラがチェックするだけです。(値をプログラム中で変更するとコンパイルエラーとなる。)
すなわち,大きな定数表(配列)をグローバル変数で与えるときにはconst修飾子をつけるとROM領域に割り当てられ,少ないRAMしか持たないH8のRAM節約になることを意味します。(関数内で大きな定数表(配列)を与える場合はconst
staticにすればよい。)
【4】スタートアップルーチン「startup3664.src」のソース
スタートアップルーチン「startup3664.src」のソース |
;************************************************************************ |
SECTION
A............................アブソリュート領域(このスタートアップルーチンのみで使用)
SECTION
P............................プログラム領域(Cで記述したプログラムのオブジェクトもここに入る)
【6】リンカオプションを記述したSUBファイルの例
INPUTオプションにstartup3664.objを加える。
OUTPUT xxxxxx
PRINT xxxxxx
INPUT
xxxxxx
INPUT c:\Progra~1\h8_3664\startup3664.obj
LIB
c:\Progra~1\h8_3664\c38hn.lib
ROM (D,X)
START
P,C,D(34),X,B(0F780)
EXIT
「ROM (D,X)」の指示でSECTION DとSECTION Xが結び付けられる。
【7】このスタートアップを利用したタイマー割り込みプログラミングの例
タイマー割り込みプログラム例1
プログラム中main()側で約33msec(0.033秒)間隔でタイマ割り込みを設定
main()関数内でループ動作をしている最中に,割り込み関数interrupt_cfunc()は0.033秒ごとに起動し,LEDのON-OFFを行なう。
このタイマ割り込みはTimerAが使われている。
/*タイマー割り込みを起動し,LEDの点滅制御を行なう*/
#include "H8_3664.h"
volatile int cnt=0;
main()
{
initLed();/*LEDの初期化*/
initTimerAInt(2);
/*タイマAによる約30Hz割り込み*/
E_INT(); /*CPU
割り込み動作許可*/
startTimerAInt();
/*タイマA起動*/
while (1)
{
if (cnt<15)
{
turnOnLed(0);
turnOffLed(1);
} else
{
turnOnLed(1);
turnOffLed(0);
}
}
}
/*割り込み関数 関数名は変更してはならない*/
void
interrupt_cfunc(void)
{
cnt++;
if
(cnt==30) cnt=0;
}
参考
以下の3つの関数は「h8_3664.h」からの抜粋したタイマー割り込み関係の関数である
/*
TimerAを利用したタイマー割り込み
割り込み関数の名前は void
interrupt_cfunc(void)で,これは
startup3664.mar中で決まっている。
void initTimerAInt(short int n)
TimerAを利用したタイマー割り込み初期化
void
startTimerAInt(void)
TimerAを利用したタイマー割り込みスタート
void
stopTimerAInt(void)
TimerAを利用したタイマー割り込みストップ
*/
/*TimerAを利用したタイマー割り込み
割り込み関数の名前はvoid
interrupt_cfunc()で,固定
TimerAを利用したタイマー割り込み初期化
引数の値とタイマー割り込み周波数
7
7812.5[Hz]
6 1953.125[Hz]
5
488.28125[Hz]
4
244.140625[Hz]
3
122.0703125[Hz]
2
30.51757813[Hz]
1
15.25878906[Hz]
0
7.629394531[Hz]
*/
/*
void initTimerAInt(short int
n)
{
TA.TMA.BIT.CKSI=n;
}
*/
#define
initTimerAInt(n) TA.TMA.BIT.CKSI=n
/*TimerAを利用したタイマー割り込みスタート*/
/*
void
startTimerAInt(void)
{
IENR1.BIT.IENTA=1;
}
*/
#define startTimerAInt() IENR1.BIT.IENTA=1
/*TimerAを利用したタイマー割り込みストップ*/
void
stopTimerAInt(void)
{
IENR1.BIT.IENTA=0;
IRR1.BIT.IRRTA=0;
}