成安造形大学コラボレーション・プロジェクト

アーティストのための汎用センサ自作応援講座

2001年1月 長嶋洋一


第4話

さて、 第3話 の続きです。 まだパネルのA/D入力コネクタとボリュームの配線が残っていましたが、 まずはそれ以外の部分、つまりLEDを点滅させるとか、そもそもAKI-H8の ソフトを開発してダウンロードする、という事ができる確認をしていなかった ので、とりあえず準備を始めました。

これ は、いつも並んでいるPowerBookとDynaBookに加えて、もう1台の PowerBook2400cを出してきたところです。DynaBookは単なる「台」です。 手前右にあるのが、初期のAKI-H8キットには付属していないために、 マニュアルの回路図を参考に自作したAKI-H8ライタです。これについて は、 このあたり に記載されていますので、参考にして下さい。ちかぢか、AKI-H8キットに 付属しているライタを製作して紹介したいと思っていますので、 これをわざわざこれから自作する必要はないでしょう。ライタ上の AKI-H8ソケットのCN4の全ピンをそのまま延長しています。
これ が、自作AKI-H8ライタのコネクタ面で、同一構成のハード(MIDIを 行うぐらい)であれば、ここにAKI-H8を挿してプログラムしてしまい、 完成したAKI-H8を「部品」として製作に使います。この基板上には、 MIDIの回路も標準で載っているというのがウリです。(^_^) これ は、AKI-H8ライタから延長したケーブルの接続部分です。

そして、基本的なLED点滅とMIDI送りの動作を確認したあとで、 このように パネルのコネクタとボリュームからの配線を行いました。 空中配線みたいなものですが、まぁこんなものです。これを配線すると、 もうマスター基板の裏の配線を修正したりするのは苦しくなりますので、 手順を踏んで進めていく必要があります。
実際のところを言えば、AKI-H8ライタから電源を供給している 時には起きなかったのに、ケースに内蔵したGORILLAに切り換えると、 A/Dデータが細かく変動する、というトラブルが発生しました。 オシロで追跡して電源による発振のようなノイズが混入している事を 確認し、この基板の裏側にA/Dラインごとにローパスフィルタとして 105を取り付けました。残り4セットは配線前だったのですが、 最初のテスト機だけは、この配線をした後での空中配線として 苦労しました。そういう事も、まぁ、あります。(^_^;)

ここではあまり詳しい事は説明しませんが、このマシンは、かなり 「AKI-H8による汎用のアナログ--MIDIインターフェース」として機能 すると思いますので、ここで忘れないうちに記録として残すことに しましょう。興味のある方はどうぞ製作してみて下さい。
まず、回路図ですが、 これ が全てです。製作のメモとして、コネクタ等のピン配置もあとから 書き込みました。この1枚だけで製作しました。あとの辻褄は、ソフト で合わせる、という事になります。(^_^;)
この回路図を上から簡単に解説すると、コネクタCN2の7本のA/D入力 を割り当てています。ボリューム以外の全ての入力には、アナログライン とGNDとの間に100Kと105を入れてフィルタとします。ボリューム(100K)の ところは105だけで十分です。 その下の3つは、それぞれP1、P2、P3というポートの下位4ビットだけと いうリッチな使い方(^_^;)で、4ビットDIPスイッチの状態を入力して います。各データは10Kとか4.7Kの集合抵抗で+5Vにプルアップ しておきます。つまりOFFでHI、ONでLOWですので、入力してから ソフトで全ビットを反転します。 いちばん下の部分は、MIDI出力とパネルLEDの点滅のためのポートです。

さて、気になるソフトですが、解説は省略しますが、ソースもオブジェクトも ここにドカンと公開します。(^_^) まずはソースプログラム。あまり美しくない のですが、まぁ開発期間が2時間ほどの手抜きですので御容赦下さい。(^_^;)

;-----------------------------------------------------------
;
;	7 channel universal A/D to MIDI : Jan. 2000
;
;-----------------------------------------------------------

;##### Port Defines #####
smr	.equ	h'0fffb0
brr	.equ	h'0fffb1
scr	.equ	h'0fffb2
tdr	.equ	h'0fffb3
ssr	.equ	h'0fffb4
rdr	.equ	h'0fffb5
p1ddr	.equ	h'0fffc0
p1dr	.equ	h'0fffc2
p2ddr	.equ	h'0fffc1
p2dr	.equ	h'0fffc3
p3ddr	.equ	h'0fffc4
p3dr	.equ	h'0fffc6
p4ddr	.equ	h'0fffc5
p4dr	.equ	h'0fffc7
p5ddr	.equ	h'0fffc8
p5dr	.equ	h'0fffca
addrah	.equ	h'0fffe0
addrbh	.equ	h'0fffe2
addrch	.equ	h'0fffe4
addrdh	.equ	h'0fffe6
adcsr	.equ	h'0fffe8
adcr	.equ	h'0fffe9
iprb	.equ	h'0ffff8
tstr	.equ	h'0fff60
tsnc	.equ	h'0fff61
tmdr	.equ	h'0fff62
tfcr	.equ	h'0fff63
toer	.equ	h'0fff90
tocr	.equ	h'0fff91
tcr0	.equ	h'0fff64
tior0	.equ	h'0fff65
tier0	.equ	h'0fff66
tsr0	.equ	h'0fff67
tcnt0	.equ	h'0fff68
gra0	.equ	h'0fff6a
grb0	.equ	h'0fff6c

;##### Vector Defines #####
	.section vector,data,locate=h'000000
	.data.l	start
	.org	h'000060
	.data.l	int_timer0

;##### Work RAM Data Defines #####
	.section ram,data,locate=h'0fef10
timer1	.res.w	1
timer2	.res.w	1
timer3	.res.w	1
tx_top	.res.w	1
tx_end	.res.w	1
data	.res.b	1
counter	.res.b	1
led	.res.b	1
ad_status	.res.b	1
ad_no		.res.b	1
ad_data		.res.b	8
channel	.res.b	1
flag	.res.b	1
offset	.res.b	1
	.org	h'0ff800
tx_fifo	.res.b	1024

;***** Constant Table Defines *****
	.section rom,data,locate=h'001000
        .data.w 500,250,200,150,125,100,80,75,67,50,40,30,25,20,15,10

;***** Reset --> Initialize --> Main Loop *****
	.section program,code,locate=h'002000
start:
	mov.l	#h'0fff0f,er7		; stack pointer set
	mov.l	#h'0fef10,er2
	mov.w	#h'0fe0,r1
	mov.b	#0,r0l
_ram_clear:
	mov.b	r0l,@er2
	inc.l	#1,er2
	dec.w	#1,r1
	bne	_ram_clear
	jsr	@sci0_init		; SCI initialize
	mov.b	#b'00100011,r0l
	mov.b	r0l,@tcr0		; Timer0 init : 2MHz clock
	bclr	#0,@tsr0		; Clear IMFA
	bset	#0,@tier0		; timer INT set
	mov.w	#1999,r0		; 1msec INT
	mov.w	r0,@gra0
	mov.b	#0,r0l
	mov.b	r0l,@p1ddr		; set : Port[1] all input
	mov.b	#0,r0l
	mov.b	r0l,@p2ddr		; set : Port[2] all input
	mov.b	#0,r0l
	mov.b	r0l,@p3ddr		; set : Port[3] all input
	mov.b	#0,r0l
	mov.b	r0l,@p4ddr		; set : Port[4] all input
	mov.b	#b'11111111,r0l
	mov.b	r0l,@p5ddr		; set : Port[5] all output
	jsr	@wait_500msec
	jsr	@dip_scan
	bset	#0,@tstr		; timer start !
	mov.b	#0,r0l
	mov.b	r0l,@ad_no
	bset.b	#3,r0l
	mov.b	r0l,@adcsr		; A/D stop
	bclr.b	#7,@adcr		; TRGE = 0
	mov.b	#b'00100000,r0l		; tx/rx start !
	mov.b	r0l,@scr
	andc.b	#b'01111111,ccr		; interrupt enable
loop:
	jsr	@ad_check
	jsr	@timer_check
	jsr	@tx_midi_check
	jmp	@loop

;***** DIP SW check *****
dip_scan:
	mov.b	@p1dr,r1l		; input DIP SW to Port[1]
	xor.b	#b'11111111,r1l
	and.b	#b'00001111,r1l
	shll.b	r1l
	mov.b	#b'00010000,r1h
	mov.w	#0,e1
	mov.w	@er1,r0			; sampling rate table
	mov.w	r0,@timer3		; set to [timer3] (A/D sampling rate)
	mov.b	@p2dr,r0l		; input DIP SW to Port[2]
	xor.b	#b'11111111,r0l
	and.b	#b'00001111,r0l
	mov.b	r0l,@channel		; set to [channel]
	mov.b	@p3dr,r0l		; input DIP SW to Port[3]
	xor.b	#b'11111111,r0l
	and.b	#b'00001111,r0l
	shll.b	r0l
	shll.b	r0l
	shll.b	r0l
	mov.b	r0l,@offset		; set to [offset]
	rts

;***** A/D Check Routine *****
ad_check:
	btst.b	#7,@adcsr		; A/D conv end ?
	bne	_ad_go
	rts
_ad_go:
	mov.b	@ad_no,r0l
	mov.b	r0l,r4l			; [r4l] = Data channel
	cmp.b	#0,r0l
	beq	_ad_1
	cmp.b	#4,r0l
	beq	_ad_1
	cmp.b	#1,r0l
	beq	_ad_2
	cmp.b	#5,r0l
	beq	_ad_2
	cmp.b	#2,r0l
	beq	_ad_3
	cmp.b	#6,r0l
	beq	_ad_3
	cmp.b	#3,r0l
	beq	_ad_4
	cmp.b	#7,r0l
	beq	_ad_4
_ad_1:
	mov.b	@addrah,r3h		; Get A/D data
	bra	_ad_next
_ad_2:
	mov.b	@addrbh,r3h		; Get A/D data
	bra	_ad_next
_ad_3:
	mov.b	@addrch,r3h		; Get A/D data
	bra	_ad_next
_ad_4:
	mov.b	@addrdh,r3h		; Get A/D data
	bra	_ad_next
_ad_next:
	inc.b	r0l
	and.b	#b'00000111,r0l
	mov.b	r0l,@ad_no
	cmp.b	#7,r0l
	beq	_ad_more
	bset.b	#3,r0l
	mov.b	r0l,@adcsr		; A/D channel = 0
	bset.b	#5,@adcsr		; next A/D start !
_ad_more:
	extu.w	r4
	extu.l	er4
	shlr.b	r3h			; R3H = now
	mov.b	r3h,r3l			;  --> r3l
	mov.b	@(ad_data,er4),r2h	; R2H = old
	cmp.b	r2h,r3l			; r3l-r2h
	bmi	_minus			; if minus
	sub.b	r2h,r3l			; r3l-r2h -> r3l
	cmp.b	#2,r3l			; r3l>2 ?
	bpl	_ad_ok
	rts
_minus:
	sub.b	r3l,r2h			; r2h-r3l -> r2h
	cmp.b	#2,r2h			; r2h>2 ?
	bpl	_ad_ok
	rts
_ad_ok:
	mov.b	r3h,@(ad_data,er4)	; now -> old
	mov.b	@channel,r0h
	or.b	#b'10110000,r0h
	jsr	@tx_fifo_set
	mov.b	@offset,r0h
	add.b	r4l,r0h
	jsr	@tx_fifo_set
	mov.b	r3h,r0h
	jsr	@tx_fifo_set
	rts

;***** SCI init / MIDI Transmit Routines *****
sci0_init:
	mov.b	#b'00000000,r0l
	mov.b	r0l,@scr
	mov.b	#b'00000000,r0l
	mov.b	r0l,@smr
	mov.b	#15,r0l
	mov.b	r0l,@brr
	mov.w	#500,r0
_sci0_wait:
	dec.w	#1,r0
	bne	_sci0_wait
	mov.b	@ssr,r0l		; (dummy read)
	mov.b	#0,r0l
	mov.b	r0l,@ssr
	mov.b	#b'00001000,r0l
	mov.b	r0l,@iprb		; SCI0-int priority UP !
	rts
tx_midi_check:
	mov.w	@tx_top,r1
	mov.w	@tx_end,r6
	cmp.w	r1,r6
	bne	_tx_exist
	rts
_tx_exist:
	btst	#7,@ssr			; test TRDE
	bne	_tx_seq
	rts
_tx_seq:
	mov.w	#0,e6
	mov.b	@(tx_fifo,er6),r0l
	mov.b	r0l,@tdr
	bclr	#7,@ssr			; Transmit !
	inc.w	#1,r6
	bclr	#2,r6h
	mov.w	r6,@tx_end
	rts
tx_fifo_set:
	mov.w	@tx_top,r6
	mov.w	#0,e6
	mov.b	r0h,@(tx_fifo,er6)	; transmit data = [r0h]
	inc.w	#1,r6
	bclr	#2,r6h
	mov.w	r6,@tx_top
	rts

;***** Timer / Counter Routines *****
wait_500msec:
	mov.l	#500,er1
_wait_1:
	jsr	@wait_1msec
	sub.l	#1,er1
	bne	_wait_1
	rts
wait_1msec:
	mov.l	#2048,er2
_wait_2:
	sub.l	#1,er2
	bne	_wait_2
	rts
int_timer0:
	push.w	r0
	mov.b	#1,r0l
	mov.b	r0l,@flag
	btst	#0,@tsr0
	bclr	#0,@tsr0		; Clear IMFA
	pop.w	r0
	rte
timer_check2:
	mov.w	@timer2,r1
	inc.w	#1,r1
	mov.w	r1,@timer2
	cmp.w	#500,r1
	beq	_timer_2
	rts
_timer_2:
	mov.w	#0,r1
	mov.w	r1,@timer2
	mov.b	@led,r0l
	bnot	#0,r0l
	mov.b	r0l,@led
	mov.b	r0l,@p5dr		; write to Port[5]
	jsr	@dip_scan
	rts
timer_check:
	mov.b	@flag,r0l
	cmp.b	#0,r0l
	bne	_timer_event
	rts
_timer_event:
	jsr	@timer_check2
	mov.b	#0,r0l
	mov.b	r0l,@flag
	mov.w	@timer3,r2
	mov.w	@timer1,r1
	inc.w	#1,r1
	mov.w	r1,@timer1
	cmp.w	r2,r1
	beq	_timer_1
	rts
_timer_1:
	mov.w	#0,r1
	mov.w	r1,@timer1
	mov.b	#0,r0l
	mov.b	r0l,@ad_no
	bset.b	#3,r0l
	mov.b	r0l,@adcsr		; A/D channel = 0
	bset.b	#5,@adcsr		; A/D start !
	rts

	.end
そして、このテキストファイルをAKI-H8ライタソフトで転送すれば とりあえず動いてしまう、というMotorolaのSフォーマット形式の オブジェクトファイルは以下のようになります。
S00E0000466C617368524F4D4D4F5426
S107000000002000D9
S1070060000021F682
S113100001F400FA00C80096007D00640050004B14
S1131010004300320028001E00190014000F000ACC
S11320007A07000FFF0F7A02000FEF1079010FE03C
S1132010F80068A80B721B5146F85E002162F82392
S113202038647F6772007F667000790007CF6B802A
S1132030FF6AF80038C0F80038C1F80038C4F80067
S113204038C5F8FF38C85E0021D25E0020767F6075
S11320507000F8006A88EF1E703838E87FE9727004
S1132060F82038B2067F5E0020A65E0022385E00AC
S113207021825A00206629C2D9FFE90F1009F11005
S11320807909000069106B80EF1428C3D8FFE80FAB
S11320906A88EF2728C6D8FFE80F10081008100831
S11320A06A88EF2954707EE8737058600002547098
S11320B06A08EF1E0C8CA8005870002AA8045870F8
S11320C00024A80158700024A8055870001EA80217
S11320D05870001EA80658700018A80358700018FE
S11320E0A8075870001223E05800001223E258009A
S10720F0000C23E4D6
S11320F45800000623E6580000000A08E8076A8827
S1132104EF1EA80758700008703838E87FE870504D
S11321141754177411030C3B78406A22000FEF1F06
S11321241C2B58B0000A182BAB0258A0000C547097
S113213418B2A20258A00002547078406AA3000F98
S1132144EF1F6A00EF27C0B05E0021B86A00EF29D1
S113215408C05E0021B80C305E0021B85470F8004A
S113216438B2F80038B0F80F38B1790001F41B50D5
S113217446FC28B4F80038B4F80838F854706B01F6
S1132184EF166B06EF181D165860000254707EB4E8
S11321947370586000025470790E000078606A28E6
S11321A4000FF80038B37FB472700B5672266B8637
S11321B4EF1854706B06EF16790E000078606AA06E
S11321C4000FF8000B5672266B86EF1654707A01D3
S11321D4000001F45E0021E67A310000000146F4B8
S10521E4547032
S11321E67A02000008007A320000000146F85470B3
S11321F66DF0F8016A88EF287E6773007F677200C7
S11322066D7056706B01EF120B516B81EF127921D2
S113221601F4587000025470790100006B81EF12CB
S11322266A08EF1C71086A88EF1C38CA5E002076BC
S113223654706A08EF28A8005860000254705E00C4
S1132246220AF8006A88EF286B02EF146B01EF107D
S11322560B516B81EF101D215870000254707901E8
S113226600006B81EF10F8006A88EF1E703838E8BB
S10922767FE87050547074
S9032000DD
ということで、なんのこっちゃ(^_^;)、と逃げないで下さいね。
これでソフトが完成したので、ケースを組み立てて この ように 完成です。(^_^)

ちなみに、実際にはソフト開発の段階でパネルの1個のボリュームでは アナログ入力が不足するので、ちょっと寄り道して、 ものを先に作ってみました。ジョイスティックで2入力、中央に右手親指用の ボタンスイッチで1入力、あとテンキーの3列を3入力として、合計で6系列の アナログ電圧源となっています。 これについては、またあとで書きたいと思います。なかなか楽しい世界です。(^_^)