目次

マイコン選定

 2007年から死蔵になっているマイコンMSP430を使います。

 トランジスタ技術2007年1月号の付録に、TIのマイコン
 MSP430F4270が同梱されていました。
  シリアルインタフェースがないというので、放置でしたが
 テスト基板を半田付けして使います。




 WindowsXPマシンでクロスコンパイルした後、JTAGを使い
 gdbによるファームウエアのダウンロードが必要とわかり
 インタフェースを作成。

 半田付けした基板は、以下。



 トランジスタ技術で紹介されていたJTAGのインタフェース
 回路では、74HC244を利用。

 74HC244の手持ちがなかったので、74LS367を使いました。
 電源は、外付けにします。

 74HC244は、ピンの並び方が嫌いなので、最も使いたくない
 ICということもあります。

 1990年頃からマイコンを扱っていれば、+5V電源は
 ありふれていて、手持ちがあったので電源を外付けに。

 回路図は、以下。



 電源には、Zennerダイオードと整流ダイオードを利用した
 簡易タイプとしています。

 トランジスタ技術の回路では、74HC244を利用して電源電圧を
 生成していました。この種類の回路では、不安定で動作しない
 経験をしているので、外部電源を使う仕様に。

 3.3V電源は、MSP430のJTAGで使うので外部電源5Vから
 簡易回路で生成しています。

 動作テスト用に作成したプログラムは、以下。

#include "hardware.h"

void init_io(void);

void main(void)
{
  /* initialize I/O */
  init_io();
  /* enter LPM0 and enable global interrupt (loop) */
  _BIS_SR(LPM0_bits | GIE);
}

/* Interrupt Service Routine(Timer A0) */
interrupt (TIMERA0_VECTOR) Timer_A(void)
{
  P5OUT ^= 0x01; /* inverse */
}

void init_io(void)
{
  /* stop WDT */
  WDTCTL = WDTPW | WDTHOLD;
  /* output -> P5.0 (pin number 26) */
  P5DIR |= 0x01 ;
  /* 0 -> P5.0 (pin number 26) */
  P5OUT &= ~0x01 ;
  /* enable CCR0 interrupt */
  CCTL0 = CCIE;
  /* initialize compare match register 0 */
  CCR0 = 20000;
  /*
    clock source : ACLK
    mode         : up counter
  */
  TACTL = TASSEL_1 | MC_1;
}

 トランジスタ技術の記事を参考にしましたが、出力レジスタ、方向レジスタ
 の使い方で?と思うところがあり、自分がいつも使っているスタイルで記述
 しました。

 組込み関係のプログラムは、初期化後、無限ループに入り
 割込みによるイベントで、必要な仕事を実現するのが定石。

 MSP430では、無限ループのかわりに、LowPowerModeに入り
 割込みによるイベントで、必要な仕事を実現するのが定石
 のようです。

 レジスタの指定ビットをセット、リセットして、論理和で
 結合ではなく、和で計算というのが定石のよう。

 レジスタの指定ビットのセット、リセットの後には
 論理和で合成という方式に慣れているので、いつも
 の論理和を使いました。

 タイマーAのコンペアマッチ割込みで、割込みハンドラである
 関数Timer_Aを起動。関数Timer_Aの中で、出力値を反転して
 LEDの点滅を例としてます。

 Timer_Aは、アップカウントモードとし、カウント値が
 レジスタCCR0と一致したなら、リセットと割込み発生
 になるようにしました。

 MSP430のカウンタは、3モードをもち、その中のひとつ
 アップカウントを利用しました。




 割込み発生で、Low Power Modeの状態から6usで起動し
 関数Timer_Aを実行します。割込みハンドラでの作業が
 終了すると、再びLow Power Modeの状態に遷移。

 P5.0(26番ピン)に、抵抗を介してLEDを接続。



 LEDの点滅で、動作を確認できました。

 ソースコードには、ヘッダファイルが含まれてます。
 ヘッダファイルの内容は、以下。

#ifndef HARDWARE_H
#define HARDWARE_H

#include <io.h>
#include <signal.h>
#include <iomacros.h>

#endif //HARDWARE_H

 Unix系のコンパイラでは、割込みはsignalで処理するので
 そのためのヘッダファイルを指定。レジスタのアドレスや
 よく利用する定数等は、io、iomacrosのヘッダファイルで
 指定しています。

 コンパイル、リンクは、最初、次のmakefileを定義し
 makeを入力しましたが、うまくいきませんでした。

tst0.elf : tst0.o
        msp430-gcc -mmcu=msp430x4270 -o tst0.elf tst0.o
tst0.o : tst0.c hardware.h
        msp430-gcc -g -O0 -mmcu=msp430x4270 -Wno-main -c tst0.c

 WindowsのDOS窓を利用しているので、バッチファイルで対応。
 バッチファイルの内容は、以下。

del *.o
del *.elf
msp430-gcc -g -O0 -mmcu=msp430x4270 -Wno-main -c tst0.c
msp430-gcc -mmcu=msp430x4270 -o tst0.elf tst0.o

 コンパイルのオプションで「-g」を入れて、デバッグのgdbを
 使えるようにしています。

 どんなアセンブリ言語に変換されるのかを、コンパイルオプション「-S」
 で指定して、生成させてみました。

	.file	"tst0.c"
	.arch msp430x4270

	.text
	.p2align 1,0
.global	main
	.type	main,@function
/***********************
 * Function `main' 
 ***********************/
main:
/* prologue: frame size = 0 */
.L__FrameSize_main=0x0
.L__FrameOffset_main=0x4
	mov	#(__stack-0), r1
	mov	r1,r4
/* prologue end (size=3) */
	call	#init_io
/* #APP */
	bis	#llo(24), r2
/* #NOAPP */
/* epilogue: frame size=0 */
	br	#__stop_progExec__
/* epilogue end (size=4) */
/* function main size 11 (4) */
.Lfe1:
	.size	main,.Lfe1-main
/********* End of function ******/

	.p2align 1,0
.global	Timer_A
.global	vector_ffec
	.type	Timer_A,@function
/***********************
 * Interrupt Service Routine `Timer_A' at 0xffec
 ***********************/
vector_ffec:
Timer_A:
/* prologue: frame size = 0 */
.L__FrameSize_Timer_A=0x0
.L__FrameOffset_Timer_A=0x4
	push	r5
	push	r4
/* prologue end (size=2) */
	xor.b	#llo(1), &0x0031
/* epilogue: frame size=0 */
	pop	r4
	pop	r5
	reti
/* epilogue end (size=3) */
/* function Timer_A size 7 (2) */
.Lfe2:
	.size	Timer_A,.Lfe2-Timer_A
/********* End of function ******/

	.p2align 1,0
.global	init_io
	.type	init_io,@function
/***********************
 * Function `init_io' 
 ***********************/
init_io:
/* prologue: frame size = 0 */
.L__FrameSize_init_io=0x0
.L__FrameOffset_init_io=0x4
	push	r5
	push	r4
/* prologue end (size=2) */
	mov	#llo(23168), &0x0120 
	bis.b	#llo(1), &0x0032
	bic.b	#llo(1),&0x0031
	mov	#llo(16), &0x0162 
	mov	#llo(20000), &0x0172 
	mov	#llo(272), &0x0160 
/* epilogue: frame size=0 */
	pop	r4
	pop	r5
	ret
/* epilogue end (size=3) */
/* function init_io size 21 (16) */
.Lfe3:
	.size	init_io,.Lfe3-init_io
/********* End of function ******/

/*********************************************************************
 * File tst0.c: code size: 39 words (0x27)
 * incl. words in prologues: 7, epilogues: 10
 *********************************************************************/

 アセンブリ言語の内容から、Cで利用するフレーム領域には
 レジスタr4、r5を割り当て。この2つのレジスタをフレーム
 ポインタに使用と理解できます。

 コンパイラの生成するアセンブリ言語コードは、コンパクトで
 プロセッサの特徴を活用した、SRAMの容量が少なくても動作に
 支障がないとわかります。

 gdbを起動する前に、msp430-gdbproxyを起動させるという
 Unix系のデバッガでは「お約束」の操作で動きました。

 msp430-gdbproxyは、DOSプロンプトから起動。

  msp430-gdbproxy msp430 LPT1{enter}




 msp430-gdbも、DOSプロンプトから起動。

  msp430-gdb tst0.elf{enter}





 JTAGインタフェースとMSP430の基板は、16ピンケーブルで
 接続し、PCとJTAGインタフェースは、パラレルケーブルで
 接続しています。




 MSP430のファームウエアをダウンロードするため
 gdbの方で次のコマンドを入力。

 gdbでは、他に次の4コマンドを加えると、大抵の
 デバッグができます。

 gdb、gdb-proxyによりMSP430の内部レジスタの値を参照できるので
 Program Counter、Stack Pointer、Status等を見れば、どんなこと
 が起きたのかを確認できます。

 break pointをソースコード上で指定できる他、ステップ動作で1行
 1行の処理結果を確認して、不具合がどこで発生しているのか特定
 しやすくなりました。

 古いマイコン基板でも、充分動くことが
 わかったので、次の作業に移ります。

 MSP430F4270は、ROMが16kバイト、RAMが256バイトで
 RAM容量が少ない印象です。


目次

inserted by FC2 system