Propeller日記 (5)

長嶋 洋一


Propeller日記(1)

Propeller日記(2)

Propeller日記(3)

Propeller日記(4)

続・Propeller日記(1)

続・Propeller日記(2)

続・Propeller日記(3)

続・Propeller日記(4)

続・Propeller日記(5)

続々・Propeller日記(1)

続々・Propeller日記(2)

続々・Propeller日記(3)

続々・Propeller日記(4)

2008年4月5日(土)

Parallax社のPropeller Demo Boardでなく、オリジナルに製作した試作実験ボードに切り替えて、 インスタレーションのために2系統ビデオ出力にトライすることにした。 前日のproto001.spinでは、ビデオ出力のポート指定が分かったところまでだったので、 proto001.spinをコピーしてリネームしたproto002.spinでいろいろと実験した。

まず最初に出て来たのは、単純にproto001.spinの中のビデオ出力関係をダブルに持つことが出来ない、 という壁だった。 VAR領域の変数、初期化、OBJ領域のTVとgrの定義を

OBJ
	midiIn : "MidiIn03"
	midiOut : "MidiOut01"
	audio : "AudioOut06"
	tv[2] : "E_TV02"
	gr[2] : "E_Graphics02"

とダブルで持って、プログラム中のtvメソッドとgrメソッドの部分をそっくりコピーして、 tv[0]とtv[1]と指定する・・・というような定番の改訂をまず、行ってみた。 すると、Propeller ToolのF10(コンパイル+ダウンロード+実行)に対して、 「Run Time Error : Memory Full」みたいな表示が出て、 ○○longsだけオーバーしているのでPropellerのRAMに入らない、と叱られた。

ここまではいくつもの仕事をどんどん快調に加えてきても何も起きなかったが、 どうやら、グラフィック表示は色々とメモリを使うようである。 仕方ないので、

  • MIDIは入力だけで出力をコメントアウト
  • デモのグラフィクス表示の大部分をコメントアウト
  • 定数エリアのデータ定義もコメントアウト
などあれこれして、ようやくメモリ不足エラーが出なくなり、Propellerに転送できた。 ところが、2つのビデオモニタが沈黙したり、何か描画しているらしいがチラついたり、 グラフィック表示してもヘンな表示になったり・・・と、試行錯誤するたびに異常となった。

ここでは試行錯誤のいちいち全ては書かないが、次第に分かってきたのは、 このデモで紹介されている(1系統の)ビデオ出力のグラフィック処理は、 けっこうPropellerのCogsの処理としては頑張っている、キチキチなデモなのだった。 倍増ではオーバーして、少しカットするとOKになるぐらい、限界ギリギリだった。

そして発見した最大の問題は、「2系統のグラフィックメモリは持てない」という事実だった。 CON領域の定数として定義している

CON
	_clkmode = xtal1 + pll16x
	_xinfreq = 5_000_000
	_stack = ($3000 + $3000 + 100) >> 2   'accomodate display memory and stack
	x_tiles = 16
	y_tiles = 12
	paramcount = 14       
	bitmap_base = $2000
	display_base = $5000
	lines = 10

の部分が問題で、少しずつ変えてコンパイルしてはビデオ画面に入るノイズの位置で実験した結果、

  • 「bitmap_base」の領域は $2000 - $4FFFF
  • 「display_base」の領域は $5000 - $7FFFF
を全て使用していることが分かった。 従って、プログラムとメモリ領域は $0000 - $1FFF に入らなければならないが、 これが既に $1F00 付近まで行っていて、増やすと越えてしまうのであった。

ビデオの1系統でこれだけ使うので、とても2チャンネルの別個のビデオを同時に表示は出来ない。 ただしこれは、

  repeat

    'clear bitmap
    gr.clear

・・・・・・・・

    'copy bitmap to display
    gr.copy(display_base)

というループで、グラフィックの1フレームの冒頭にグラフィックメモリをクリアし、 そこに描画処理をして、最後にこれを表示メモリに転送する、 というダブルバッファであることが分かった。 フリッカ(ちらつき)対策であり、この最後の「gr.copy(display_base)」をコメントアウトすると、 見事にフリッカ画面となった。

そこで、今回のシステムでは仕様として2系統ビデオ出力を優先することにして、 ダブルバッファを捨てることにした。 つまり、メインのCogのループごとの冒頭に「gr.clear」を行わない代わりに、 ループの最後の「gr.copy(display_base)」も行わない。 これで、2系統のグラフィックのための定義も

CON
	_clkmode = xtal1 + pll16x
	_xinfreq = 5_000_000
	_stack = ($3000 + $3000 + 100) >> 2   'accomodate display memory and stack
	x_tiles = 16
	y_tiles = 12
	paramcount = 14       
	bitmap_base1 = $2000
	bitmap_base2 = $5000
	display_base1 = $2000
	display_base2 = $5000
	lines = 10

と、それぞれシングルだけ持つグラフィックメモリに対して描画処理を行えばよい。 つまり、昔のコンピュータの「ストレージ管」ディスプレイみたいなものであり、 どんどん上から塗りつぶしていくグラフィックとなる。 これは、コンテンツの方で工夫すればいいわけである。

いろいろ半日ほど悩んだ結果として、とりあえず2系統のビデオ出力を生成しながら、 MIDI入力に対応してサウンドを出したり、画面クリアをしたり、描画パラメータを変化させる、 という proto002.spin を作ってみた。 動作している風景は以下である。 パソコン無しに、グラフィックチップもシリアル用UARTもサウンドチップも無く全てソフトウェアだけで、 これだけの処理を淡々とこなす、というのは、ちょっと考えるとなかなかのものである。

 

2008年4月6日(日)

この日は半日かけて、Webサーバに上げたここまでのPropeller日記を読み返して、 全体の再整理をしたりバグを訂正したりしただけで終わった。 すっかり忘れていたが、Diary02で「_stack」についてちゃんと書いてあった。 この予約語の意味は、ちょうど直面している問題に関係したものだった。 その横ではずっと、実験用試作ボードのPropellerがずっと、2台のビデオモニタにグラフィクスを生成し続けた。

2008年4月7日(月)

Propellerによるスタンドアロンのインスタレーション、という目標に向けて、 まずはグラフィック関係を詳しく調べてみることにした。 ここまでの手応えとしては、かなりメモリ占有度が高い状況なので、 いくらでもソフトウェア部品を増設していける、という事でもないので、 常に残りメモリを気にしながらの作業となりそうだ。

proto002.spinをコピーしてリネームしたMainオブジェクトproto003.spinで、 テンポラリ変数を配列で持つのはOK、と確認したので、 とりあえずリアルタイムのグラフィック演算の定数をテンポラリ変数にして、 MIDIから色々と変化させてみることにした。 また、E_Graphics02.spinを見ると、テキストを表示するために多量のフォントデータを持っていたので、 これをコピーしてリネームしたE_Graphics03.spinに対して、大幅な削減(でもグラフィックは同等に表示)を目指した。

・・・時間はそこそこかかったが、結果はかなり地味である。 Mainはとりあえず proto003.spin となり、グラフィックのオブジェクトも E_Graphics03.spin となった。 ここまでで、以下のように、けっこうな残りスペースを作ることができた。

続きは明日だが、いよいよ入学式とか学科会議とか大学院ガイダンスがあるので、 ここからの進みは遅々としたものになるかもしれない。

2008年4月14日(月)

先週は、火曜日に雨模様の中で 入学式 があり、さらに水曜日からは連日、学科会議、大学院ガイダンス、学科ガイダンス、履修相談、と予定が続いて、 予想していたものの、プログラミングはほとんど進展しなかった。 この間に進めたのは、インスタレーションとしての手法、センサ、グラフィクス、 サウンドなどのシステム構成要素について、合間の時間に検討したぐらいである。

トラ技の編集者とのメイルで、記事の完成を5月中旬、と繰り上げて宣言したので、 ここからちょうど1ヶ月が、記事の執筆期間となる。 システムの構想・設計・実験・試作と並行しての執筆となるので、この日記では、 さらにその裏側をメモしていくことにした。 記事の末尾の「参考文献」のところでは、このページのURLを公開する予定なので、 この日記も、あと1ヶ月でとりあえず終了となる。

インスタレーションの中ではセンサを使うことになるが、 まだそのインターフェースを実験していなかったので、この部分について検討した。 Propellerでは、基本的にビット単位のデジタル(シリアル)入力となるので、 A/D入力についても、カウンタのパルスを計数する、というのが基本となる。 このためには、外部に「V/Fコンバータ」があればよい。 そこで、かつて活用していた「74124」(汎用dualのVCO)をネットで調べてみたが、 どうもこれは廃品種となった模様である。 駄目モトで、とりあえず「世界中のディーラーに打診」というサイトに、 50個、発注依頼しておいた。

次にネットで検索して発見したのが、「74HC4046」である。 これはVCOとPLLとが一体になったものであるが、 データシート を見ると、以下のように、PLLを無視してVCOだけでも、なんとか使えそうである。 そこでさっそくネットで発注してみた。 パッケージがまたまたDIPでないので苦労しそうだが仕方ない。

そして、Propeller Demo Boardには「コンデンサマイク入力」というのがあった、 と思い出して、サンプルプログラムを調べてみることにした。 既に制作が進んでいる実験試作ボードでなく、マイクまで搭載されているPropeller Demo Boardをパソコンに接続して、 以下のサンプルを呼び出してみた。

このプログラムでは「microphone_to_vga.spin」がTopオデジェクトであり、 起動すると最初に呼び出す「vga_512x384_bitmap.spin」が、 刻々とサンプリングされたオーディオサンプルのポイント値をVGAビットマップに書き出している。 VGAモニタ画面は、マイクの入力サウンドをリアルタイム表示するオシロスコープとなった。 「vga_512x384_bitmap.spin」は並列処理として、このビットマップのデータをVGA画像出力している。

これまでPropellerのプログラムを色々と調べたおかげで、新しいプログラムを見ても、 だいたいの予想がつくようになってきた。 A/D変換の部分については、ピンとして2本を用いて、 比較対象の信号を出力しつつ、入力とミックスして逐次比較している模様であった。

ここで新しい発見としては、2つのオブジェクトの間で定数の共有をしたい場合の書式として、 microphone_to_vga.spinの以下の部分

CON
  _clkmode = xtal1 + pll16x
  _xinfreq = 5_000_000
  tiles    = vga#xtiles * vga#ytiles
  tiles32  = tiles * 32

OBJ
  vga : "vga_512x384_bitmap"

と、vga_512x384_bitmap.spinの以下の部分

CON
' 512x384 settings - signals as 1024 x 768 @ 67Hz
  hp = 512      'horizontal pixels
  vp = 384      'vertical pixels
  hf = 8        'horizontal front porch pixels
  hs = 48       'horizontal sync pixels
  hb = 88       'horizontal back porch pixels
  vf = 1        'vertical front porch lines
  vs = 3        'vertical sync lines
  vb = 28       'vertical back porch lines
  hn = 1        'horizontal normal sync state (0|1)
  vn = 1        'vertical normal sync state (0|1)
  pr = 35       'pixel rate in MHz at 80MHz system clock (5MHz granularity)
' Tiles
  xtiles = hp / 32
  ytiles = vp / 32
' H/V inactive states
   hv_inactive = (hn << 1 + vn) * $0101

との、「#」を使った対応関係があった。 今回のシステムではVGAでなくNTSCビデオにしたいので、このライブラリを使う場合には、 VGAの部分はカットして、さらにオーディオサンプリングの部分を子オブジェクトに移動して、 Topからピーク値を参照するような構造に変更することを目指すことになるが、 ちょっとこれは簡単ではなさそうである。

2008年4月15日(火)

他にもA/D変換のようなサンプルが無いか、と調べているうちに、 というデモを発見した。 他に呼び出されているオブジェクトは、既に出て来たものなので省略した。 この「RCTIME_DEMO.spin」では、ピンに接続されたCR時定数を刻々とビデオモニタに出力する。 そこで、抵抗Rにボリュームを使うと、以下のようにアナログ値の表示のようになる。

ここで驚いたのは、「RCTime.spin」の以下の部分である。 つまり、サンプリングのたびに、いったんピンを出力に設定して信号を出してコンデンサに充電し、 次にそのピンを入力に設定変更して、CR時定数により放電されて電圧がスレショルドを越えるまで待つ、 ということで計測しているのだった。

  repeat
    outa[pin] := state                                  ' set pin to state
    dira[pin] := 1                                      ' make pin an ouput
    time.pause1ms(1)                                    ' allow cap to (dis)charge
    dira[pin] := 0                                      ' make pin an input
    rctemp := cnt                                       ' get current counter
    waitpeq(1-state,|< pin, 0)                          ' wait for state change on pin
    rctemp := || (cnt - rctemp)                         ' calculate duration
    rctemp := rctemp - 1600                             ' adjust for instructions (for zero)
    rctemp := rctemp >> 4                               ' scale value (divide by 16)
    long [rcvalueaddress] := rctemp                     ' move result to target

Propellerはピンが基本的に単独(シリアル)であること、 そして各Cogに仕事を割り振ってしまえば、 それぞれがいかに冗長に待っていても全体のパフォーマンスに関係ないこと、 を考えればうまい手であるが、まだまだこの発想は思い付かなかった。

「A/D変換のためには外部にV-Fコンバータを」という構想についても、 これは間違いではないが、Propellerのシステムでは、同じピンを双方向に使う、 というこのサンプルのような発想をすれば、外付けのV/Fコンバータ回路なども省略できそうである。 汎用センサ(電圧出力)に対応したA/D変換というよりも、 センサごとに特化して、センサデバイスによくある抵抗値変化をこの方法で検出するなど、 センシング手法を考えた方がよさそうである。

2008年4月16日(水)

ビデオでなくVGA出力である「microphone_to_vga.spin」だが、 マイクの感度を上げてみると以下のように綺麗にサウンドが表示される。

これは「音センサ」としても捨て難いので、無謀と分かっていながら、 ここからビデオ出力への改造に挑戦してみた。 Propeller Toolでメモリ使用状況を見ると、以下のように、 VGA出力のためのグラフィックメモリとして共有RAMの大部分を使用している。

これでは既存のビデオ出力オブジェクト群と統合しただけで、 「メモリが足りません」と叱られてコンパイルが失敗するのは確実である。 それを承知で、Propeller Demo Boardに対応した過去のオブジェクトを発掘して、 とりあえずエラーが出ないところまで、グラフィックメモリの割り当てを無理矢理に削減して、 「何か動く」ものを作ってみた。 以下のように、ビデオモニタとVGAモニタの両方に、サウンド入力に対応して動く何かが出ているが、 音圧がオーバーフローすると、ビデオ出力は真っ黒に昇天する。(^_^;)

 

 

このTopオブジェクトは microphone_001.spin であり、冒頭のCON領域の定義で、

CON
  _clkmode = xtal1 + pll16x
  _xinfreq = 5_000_000
  tiles    = vga#xtiles * vga#ytiles
  tiles32  = tiles * 8

と、本来は32倍しなければならない領域を8倍と、 1/4のサイズに無理矢理に抑えることで、コンパイルに通るメモリサイズとしている。 そのため、プログラムは勝手にこの上のアドレス領域もどんどん更新していくので、 ビデオ出力画面にも何かノイズのようなものが出て、それがマイクの音量とともに幅を変化させている。 きちんと領域確保・初期化できていないので、VGA出力もヘンになっていて、 音量が大きくなると色々な矩形が現れて、まぁ暴走による現象ではあるが、 インスタ的にも面白いことになった。 かなり無謀であるが、とりあえずここをスタートラインとした。 暴走しても「F10」で一瞬にして簡単にリトライできるからこそ、の実験である。

・・・あれこれ実験してみて、とりあえずマイクからの音に反応して、 ビデオモニタにサウンドのピーク値(閾値を越えたものだけ)を数字で表示する、 というものが出来た。それが microphone_002.spin である。 ここでは以下のように、Topオブジェクト中でサウンド追従のアセンブラルーチンと、 それをメインとして無限ループで呼び出すものの両方が入っているので、 他のモジュールと組み合わせるには適していないが、「サウンドセンサ」として使える、 という事を検証できた。

CON
	_clkmode = xtal1 + pll16x
	_xinfreq = 5_000_000
	bits = 14                     'try different values from table here
	attenuation = 0               'try 0-4
	averaging = 13                '2-power-n samples to compute average with

OBJ
	Num : "E_Numbers02"
	TV : "E_TV_Terminal02"

VAR
	long mic

PUB start | i,dummy, para, p1
	Num.Init                      { Num.Init MUST be called before first object use. }
	para := TV.Start1(12)
	dummy := TV.Start2
	TV.out(0)                     { display home }
	TV.Str(string("TV_port_Cog ="))
	TV.Str(Num.ToStr(para, Num#DEC))
	TV.Str(string(", Graphic_driver_Cog ="))
	TV.Str(Num.ToStr(dummy, Num#DEC))

	cognew(@asm_entry, @mic)

	repeat
		dummy := mic
		if(dummy <> p1)
			para := dummy - 260
			if(para > 0)
				TV.Str(Num.ToStr(para, Num#DEC))
			p1 := dummy

DAT
              org

asm_entry
              mov       dira,asm_dira                   'make pin 8 (ADC) output
              movs      ctra,#8                         'POS W/FEEDBACK mode for CTRA
              movd      ctra,#9
              movi      ctra,#%01001_000
              mov       frqa,#1
              mov       asm_cnt,cnt                     'prepare for WAITCNT loop
              add       asm_cnt,asm_cycles

:loop         waitcnt   asm_cnt,asm_cycles              'wait for next CNT value (timing is determinant after WAITCNT)
              mov       asm_sample,phsa                 'capture PHSA and get difference
              sub       asm_sample,asm_old
              add       asm_old,asm_sample
              add       average,asm_sample              'compute average periodically so that
              djnz      average_cnt,#:avgsame           'we can 0-justify samples
              mov       average_cnt,average_load
              shr       average,#averaging
              mov       asm_justify,average
              mov       average,#0                      'reset average for next averaging
:avgsame
              max       peak_min,asm_sample             'track min and max peaks for triggering
              min       peak_max,asm_sample
              djnz      peak_cnt,#:pksame
              mov       peak_cnt,peak_load
              mov       x,peak_max                      'compute min+12.5% and max-12.5%
              sub       x,peak_min
              shr       x,#3
              mov       trig_min,peak_min
              add       trig_min,x
              mov       trig_max,peak_max
              sub       trig_max,x
              mov       peak_min,bignum                 'reset peak detectors
              mov       peak_max,#0
:pksame
              cmp       mode,#0                 wz      'wait for negative trigger threshold
if_z          cmp       asm_sample,trig_min     wc
if_z_and_c    mov       mode,#1
if_z          jmp       #:loop
              cmp       mode,#1                 wz      'wait for positive trigger threshold
if_z          cmp       asm_sample,trig_max     wc
if_z_and_nc   mov       mode,#2
if_z          jmp       #:loop
              sub       asm_sample,asm_justify          'justify sample to bitmap center y
              sar       asm_sample,#attenuation         'this # controls attenuation (0=none)
              add       asm_sample,#384 / 2
              mins      asm_sample,#0
              maxs      asm_sample,#384 - 1

              wrlong    asm_sample,par

              jmp       #:loop

asm_cycles    long      |< bits - 1                     'sample time
asm_dira      long      $00000200                       'output mask
average_cnt   long      1
peak_cnt      long      1
peak_load     long      512
mode          long      0
bignum        long      $FFFFFFFF
average_load  long      |< averaging
asm_justify   res       1
trig_min      res       1
trig_max      res       1
average       res       1
asm_cnt       res       1
asm_old       res       1
asm_sample    res       1
asm_mask      res       1
asm_data      res       1
x             res       1
y             res       1
peak_min      res       1
peak_max      res       1

ここで部品が届いたので、Propeller Demo Boardでなく、 オリジナルの実験試作ボードの方に、マイク入力回路と、 サンプルにあったCR時定数回路の可変RのところにCdSを使って、 いずれも搭載してみることにした。 既にピンとして確定しているのは、

  • P8/9/10 - ビデオ出力(A)
  • P12/13/14 - ビデオ出力(B) - Propeller Demo Boardと同じ
  • P24/25 - Audio出力(ステレオ)
  • P26 - MIDI Output
  • P27 - MIDI Input
  • P28/29 - シリアルEEPROM用
  • P30/31 - ホスト接続用
である。 マイク入力には2本、CR時定数の計測には1本が必要なので、ここでは
  • P15 - CR時定数(Cds照度センサ)
  • P16/17 - マイク入力
としてみた。 回路図はいずれもParallax社のサンプルをそのまま参考にして、 ピン(ポート)番号だけオリジナルとして、以下のようになった。

回路そのものは簡単なので、まずは microphone_002.spin をコピーしてリネームした「microphone_003.spin」を作って、 以下の赤字の部分だけを変更してみると、見事にマイク入力でビデオ画面に数値を表示した。

・・・
DAT
              org

asm_entry
              mov       dira,asm_dira                   'make pin 8 (ADC) output
              movs      ctra,#16                         'POS W/FEEDBACK mode for CTRA
              movd      ctra,#17
              movi      ctra,#%01001_000
              mov       frqa,#1
              mov       asm_cnt,cnt                     'prepare for WAITCNT loop
              add       asm_cnt,asm_cycles
・・・
asm_cycles    long      |< bits - 1                     'sample time
asm_dira      long      $00020000                       'output mask
average_cnt   long      1
・・・

また、CdSをセンサ(可変抵抗)としたRC時定数センサについても、 RCTIME_DEMO.spin をコピーしてリネームした「RCTIME_001.spin」を作って、 以下の赤字の部分だけを変更してみると、見事にCdSの照度に対応してビデオ画面に数値を表示した。

CON
	_clkmode = xtal1 + pll16x
	_xinfreq = 5_000_000
	_stack = ($3000 + $3000 + 100) >> 2   'accomodate display memory and stack
	x_tiles = 16
	y_tiles = 12
	paramcount = 14       
	bitmap_base = $2000
	display_base = $5000
	lines = 5
	thickness = 2

VAR
	long tv_status    '0/1/2 = off/visible/invisible           read-only
	long  tv_enable     '0/? = off/on                            write-only
	long  tv_pins       '%ppmmm = pins                           write-only
	long  tv_mode       '%ccinp = chroma,interlace,ntsc/pal,swap write-only
	long  tv_screen     'pointer to screen (words)               write-only
	long  tv_colors     'pointer to colors (longs)               write-only               
	long  tv_hc         'horizontal cells                        write-only
	long  tv_vc         'vertical cells                          write-only
	long  tv_hx         'horizontal cell expansion               write-only
	long  tv_vx         'vertical cell expansion                 write-only
	long  tv_ho         'horizontal offset                       write-only
	long  tv_vo         'vertical offset                         write-only
	long  tv_broadcast  'broadcast frequency (Hz)                write-only
	long  tv_auralcog   'aural fm cog                            write-only
	long    colors[64]
	word screen[x_tiles * y_tiles]
	byte  x[lines]
	byte  y[lines]
	byte  xs[lines]
	byte  ys[lines]
	long RCValue
 
OBJ
	tv    : "tv"
	gr    : "graphics"
	RC    : "RCTIME"
	Num   : "Numbers"

PUB start | i,dx,dy
	'start tv
	longmove(@tv_status, @tvparams, paramcount)
	tv_screen := @screen
	tv_colors := @colors
	tv.start(@tv_status)
	'init colors
	 repeat i from 0 to 64
		colors[i] := $00001010 * (i+4) & $F + $2B060C02
	'init tile screen
	repeat dx from 0 to tv_hc - 1
		repeat dy from 0 to tv_vc - 1
			screen[dy * tv_hc + dx] := display_base >> 6 + dy + dx * tv_vc + ((dy & $3F) << 10)
	'start and setup graphics
	gr.start
	gr.setup(16, 12, 128, 96, bitmap_base)

	'Initialize RCValue
	RCValue := 0
	RC.start(15,1,@RCValue )

	repeat
		'clear bitmap
		gr.clear
		'draw text
		gr.textmode(1,1,7,5)
		gr.colorwidth(1,0)
		gr.text(0,90,string("Parallax RCTIME background demo"))
		'display text of RCtime value
		gr.text(0,50,Num.ToStr(RCValue, 10))
		'copy bitmap to display
		gr.copy(display_base)

DAT
tvparams                long    0               'status
                        long    1               'enable                        
                        'long   %011_0000       'pins      Old Board
                        long    %001_0101       'pins      New Board                        
                        long    %0000           'mode
                        long    0               'screen
                        long    0               'colors
                        long    x_tiles         'hc
                        long    y_tiles         'vc
                        long    10              'hx
                        long    1               'vx
                        long    0               'ho
                        long    0               'vo
                        long    60_000_000'_xinfreq<<4 'broadcast
                        long    0               'auralcog

これで、とりあえず以下のように、Propeller Demo Boardでなく、 自前のハードウェアで、コンデンサマイクによるサウンドのセンサと、 CdSによる明るさセンサ(CR時定数計測)が実際に動いた。

 

ただし、それぞれ単独・完結したサンプルプログラムそのもので走っているので、 これまでオリジナル開発してきたオブジェクトと同様に、 このセンサ部分のソフトウェアを解析・改造して、 ライブラリとして「ソフトウェア部品」化する必要がある。 これは明日以降の課題としよう。

2008年4月17日(木)

1限から大学院の講義、午後には連続して会議、とロクにまとまった時間が取れないので、 ハードウェア実験でなく、昨日の宿題のソフトウェア改造の作業を合間に進めることにした。 この時点で、作業ディレクトリは以下のようになっている。
ドライブ C のボリューム ラベルは ACER です
ボリューム シリアル番号は 8861-32F2 です

C:\Propeller のディレクトリ

04/17/2008  11:09 AM    DIR          .
04/17/2008  11:09 AM    DIR          ..
04/07/2008  04:20 PM    DIR          Archive
03/28/2008  11:36 AM             6,370		AudioOut06.spin
02/28/2008  11:31 AM    DIR          CDROM
02/18/2008  11:18 AM    DIR          Education
04/15/2008  06:16 PM             1,078		exp101.spin
03/30/2008  02:51 PM           117,356		E_Graphics01.spin
03/30/2008  03:51 PM           117,340		E_Graphics02.spin
04/07/2008  03:40 PM            64,424		E_Graphics03.spin
03/30/2008  01:29 PM             9,340		E_Numbers01.spin
03/30/2008  01:29 PM             9,340		E_Numbers02.spin
03/30/2008  02:51 PM            28,563		E_TV01.spin
03/30/2008  03:51 PM            28,555		E_TV02.spin
03/30/2008  02:51 PM             4,642		E_TV_Terminal01.spin
03/30/2008  04:17 PM             4,701		E_TV_Terminal02.spin
02/16/2006  09:00 AM            60,594		Graphics.spin
04/02/2008  02:25 PM    DIR          kari
02/18/2008  04:22 PM    DIR          Library
03/10/2008  12:51 PM    DIR          Manuals
04/16/2008  12:58 PM             4,201		microphone_001.spin
04/15/2008  06:35 PM             6,322		microphone_001_tmp.spin
04/16/2008  01:00 PM             4,201		microphone_002.spin
04/16/2008  04:22 PM             4,202		microphone_003.spin
06/09/2006  01:34 AM             6,446		microphone_to_vga.spin
03/19/2008  08:13 AM             3,645		MidiIn03.spin
03/19/2008  04:55 PM             2,727		MidiOut01.spin
02/15/2006  07:54 PM            42,946		Numbers.spin
04/07/2008  04:23 PM             4,568		proto003.spin
03/07/2006  02:19 PM             4,756		RCTime.spin
02/19/2006  11:53 PM             9,856		RCTIME_DEMO.spin
03/07/2006  02:02 PM             1,510		Timing.spin
11/16/2005  05:17 PM            28,312		tv.spin
06/06/2006  10:51 PM             8,873		vga_512x384_bitmap.spin
              27 個のファイル             594,726 バイト
               8 個のディレクトリ  68,108,861,440 バイトの空き領域

この中で、ソフトウェア部品として確定しているオブジェクト類は、以下である。

  • AudioOut06.spin
  • E_Graphics02.spin
  • E_Graphics03.spin
  • E_Numbers02.spin
  • E_TV02.spin
  • E_TV_Terminal02.spin
  • MidiIn03.spin
  • MidiOut01.spin

また、スタンドアロンとして動作する(Topとなる)オブジェクト類は、以下である。

  • microphone_003.spin
  • exp101.spin
  • proto003.spin
  • RCTIME_DEMO.spin

全てを同時に1つのシステムに混在させるのは、Cogsの制限を越えるので無理であるが、 仕様に応じて自在に取捨選択できるようにしたい、という戦略である。 いま対象としているのは、「microphone_003.spin」「RCTIME_001.spin」の2つであるが、 いずれもTopオブジェクト内でアセンブラの無限ループによりセンシングしているがので、 これをTopから呼ばれる子プロセスに改造する、という事になる。

まずは、センサ情報をテキスト表示させるために、 exp101.spinをコピーしてリネームしたexp102.spinを使うことにした。 ここからは、ビデオ出力にフルグラフィック表示するために削減改造したE_Graphics03.spinでなく、 E_TV_Terminal02.spinを参照するE_Graphics02.spinを呼び出している。 追加機能として、表示テキストの色のパラメータを持たせたので、 マイクの音響センサを緑色で、CdSのCR時定数センサを赤色で表示することにした。

いくつかの実験の結果として、Topとして「exp102.spin」に対して、

というソフトウェアを完成した。 動作状況は以下のようなもので、マイクの音響とCdsの照度の両方をセンシング表示している。 ここにバックグラウンド処理としてMIDIの入出力を加えたとしても、センシングの処理能力が低下しない、 というのがPropellerの強味である。

 

 

「exp102.spin」のメイン処理の部分は以下のようになっていて、 それぞれのセンサに対してデータをポーリングしているが、 データの取得方法は異なっている。

OBJ
  mic : "microphone_004"
  RC : "RCtime001"

VAR
  long RCValue

PUB Main | dummy, para, p1, p2
  Num.Init                      { Num.Init MUST be called before first object use. }
  para := TV.Start1(12)
  dummy := TV.Start2
  TV.out(0)                     { display home }
  TV.Str(string("TV_port_Cog ="))
  TV.Str(Num.ToStr(para, Num#DEC)) 
  TV.Str(string(", Graphic_driver_Cog ="))
  TV.Str(Num.ToStr(dummy, Num#DEC)) 
  dummy := mic.start
  TV.Str(string(", microphone_Cog ="))
  TV.Str(Num.ToStr(dummy, Num#DEC)) 
  RCValue := 0
  dummy := RC.start(15,1,@RCValue )
  TV.Str(string(", RCtime_Cog ="))
  TV.Str(Num.ToStr(dummy, Num#DEC)) 
 
  repeat
    dummy := mic.input(350)
    if(dummy <> p1)
      if(dummy > 0)
        TV.gr_test(1)
        TV.Str(Num.ToStr(dummy, Num#DEC))
      p1 := dummy 
    dummy := RCValue
    if(dummy <> p2)
      if(dummy > 2000)
        TV.gr_test(2)
        TV.Str(Num.ToStr(dummy, Num#DEC))
      p2 := dummy 

「microphone_004.spin」の方では、以下のような処理に対応して、 Topからメソッドを呼び出した返り値として取得している。 つまり、「microphone_004.spin」の中に定義したlong変数micに、 アセンブラルーチン中でPARレジスタにより指定したwrlong命令で書き込んで、 これをメソッドinputの返り値としている。 Propellerアセンブラで子メソッドを記述する場合の典型例である。

VAR
  long mic

PUB start
  return cognew(@asm_entry, @mic)

PUB input(level) : result
  result := (mic - level) #> 0

DAT
              org
asm_entry
・・・
              wrlong    asm_sample,par
              jmp       #:loop

それに対して「RCTIME_001.spin」では、以下のような処理に対応して、 メソッドrctimeに与えるパラメータとして、 返り値を格納する変数のアドレス(ポインタ)を指定している。 Topオブジェクト内に定義したlong変数RCValueをこれで与えて、 結果としてRCValueに入った値を読み出している。 spin言語で子メソッドを記述する場合の典型例である。

PUB start(pin, state, rcvalueaddress)
  return cognew(rctime(pin, state, rcvalueaddress), @rcstack)

PUB rctime(pin, state, rcvalueaddress)
  repeat
    outa[pin] := state                                  ' set pin to state
    dira[pin] := 1                                      ' make pin an ouput
    pause1ms(1)                                         ' allow cap to (dis)charge
    dira[pin] := 0                                      ' make pin an input
    rctemp := cnt                                       ' get current counter
    waitpeq(1-state,|< pin, 0)                          ' wait for state change on pin
    rctemp := || (cnt - rctemp)                         ' calculate duration
    rctemp := rctemp - 1600                             ' adjust for instructions (for zero)
    rctemp := rctemp >> 4                               ' scale value (divide by 16)
    long [rcvalueaddress] := rctemp                     ' move result to target

比較的短時間で、2種類の異なったバックグラウンド処理をソフトウェア部品として切り出すことができた。 ようやく、Propellerのソフトウェアもちょっと身近になってきたようである。 まだこの「exp102.spin」はテキスト表示の暫定システムなので、 次にはいよいよ、2画面ビデオ出力グラフィクスとこのセンサ群を組み合わせていくことになる。

2008年4月18日(金)

この日は新学期の最初のゼミなどがあったが、午後にまとまった時間があったので、 音楽情報科学研究会の予稿 を一気に作ってしまった。 長いことAKI-H8で止まっていたマイコンの話題が、 ここでPropellerの紹介とともにいよいよ新展開することになる。 末尾にはこの日記のURLも書いたので、発表とともにWeb公開となる。 トラ技の末尾の参考文献には、逆にこの音情研の資料をreferするつもりである。

2008年4月24日(木)

今週は、月曜日と火曜日は講義があり、 火曜日の午後から東京に行ってサントリーホールのコンサートで1泊。 ・・・などとあまり時間が取れない。 実験は進んでいないが、トラ技の記事を書き始めてみると、 Propellerの説明だけで分量に達してしまいそうで、悩ましい。 製作記事の余地を残してPropellerをいかに説明するか、 これはけっこう、大変かもしれない。

2008年5月10日(土)

前回の日記から2週間ほど経過した。

この間に、「とりあえず」版(途中まで)をトラ技に送ったり、 急逝した父の葬儀で9日ほど筑波に滞在したりして、 Propellerについてはまったくストップしていた。 編集部からのメイルで「既に超過している」とのことで(^_^;)、 これまでに書いた原稿から削減しつつ、単発のまとめた記事にする、 という作業である。

また、Sketching in Hardware08 の招待も来たので、 Propellerネタをアメリカで発表することになりそうである。 トラ技と、学会発表と、Sketchingと、さらに大学院での研究と、 すべて同時進行で効率良くやっていこう。

2008年5月11日(日)

これまでに制作した実験システムを融合させて、ビデオインスタレーションとなる雛形を作った。 迷ったのは、Cogsの制約でどの機能を残してどの機能を捨てるか、であった。 最終的には、子プロセスとして
  • E_Graphics03.spin
  • E_TV02.spin
  • MidiOut01.spin
  • microphone_004.spin
  • RCtime001.spin
を使用して、グラフィックは独立2画面描画とし、 センサにはサウンド(マイク)と照度(CdS)、 そして外部インターフェースはMIDI出力を採用した。

とりあえず、グラフィックのプログラミング以前の、 動作確認のための「proto005.spin」は以下である。

{{ proto005.spin }}  

CON
  _clkmode = xtal1 + pll16x
  _xinfreq = 5_000_000
  _stack = ($3000 + $3000 + 190) >> 2   'accomodate display memory and stack
  x_tiles = 16
  y_tiles = 12
  x_origin = 128
  y_origin = 96
  bitmap_base1 = $2000
  bitmap_base2 = $5000

VAR
  long  tv_status1, tv_enable1, tv_pins1, tv_mode1, tv_screen1, tv_colors1
  long  tv_hc1, tv_vc1, tv_hx1, tv_vx1, tv_ho1, tv_vo1, tv_broadcast1, tv_auralcog1
  long  tv_status2, tv_enable2, tv_pins2, tv_mode2, tv_screen2, tv_colors2
  long  tv_hc2, tv_vc2, tv_hx2, tv_vx2, tv_ho2, tv_vo2, tv_broadcast2, tv_auralcog2
  long  colors[64]
  word  screen1[x_tiles * y_tiles], screen2[x_tiles * y_tiles]
  long  RCValue

OBJ
  midiOut : "MidiOut01"
  tv[2] : "E_TV02"
  gr[2] : "E_Graphics03"
  mic : "microphone_004"
  RC : "RCtime001"

PUB start | i, k, dx, dy, dummy, para, dark, p1, p2
  midiOut.start(26)
  longmove(@tv_status1, @tvparams, 14)
  tv_screen1 := @screen1
  tv_colors1 := @colors
  tv[0].start(@tv_status1)
  longmove(@tv_status2, @tvparams, 14)
  tv_status2[2] += %0101
  tv_screen2 := @screen2
  tv_colors2 := @colors  
  tv[1].start(@tv_status2)
  gr[0].setup(x_tiles, y_tiles, x_origin, y_origin, bitmap_base1)
  gr[1].setup(x_tiles, y_tiles, x_origin, y_origin, bitmap_base2)                                      a
  mic.start
  RCValue := 0
  RC.start(15,1,@RCValue )
  para := 1

  repeat dx from 0 to tv_hc1 - 1
    repeat dy from 0 to tv_vc1 - 1
      screen1[dy * tv_hc1 + dx] := bitmap_base1 >> 6 + dy + dx * tv_vc1 + ((dy & $3F) << 10)
      screen2[dy * tv_hc1 + dx] := bitmap_base2 >> 6 + dy + dx * tv_vc1 + ((dy & $3F) << 10)
  repeat i from 0 to 63
    colors[i] := $00001010 * ( (i+4) & $F ) + $2B060C02

  repeat

    k++
    if ++dark > 123
      dark := 0
      gr[0].clear
      gr[1].clear

    'draw spinning triangles
    gr[0].colorwidth(3,0)
    gr[1].colorwidth(para,0)
    repeat i from 1 to 8
      gr[0].vec(0, 0, (k & $7F) << 3 + i << 5, k << 6 + i << 8, @vecdef)
      gr[1].vec(0, 0, (k & $7F) << 3 + i << 5, k << 6 + i << 8, @vecdef)

    'draw expanding pixel halo
    gr[1].colorwidth(1,k)
    gr[1].arc(0,0,80,30,-k<<5,$2000/9,9,0)
    

    'draw spinning stars
    gr.colorwidth(dark/30+1,0)
    repeat i from 0 to 7
      gr[0].vecarc(0,0,30,30,-(i<<10+k<<6),$A0,-(k<<7),@vecdef2)

    dummy := mic.input(350)
    if(dummy <> p1)
      if(dummy > 0)
        midiOut.fifoset($B00000 + (dummy & $7F))
        gr[0].clear
        gr[1].clear
      p1 := dummy

    dummy := RCValue
    if(dummy <> p2)
      if(dummy > 2000)
        para := (dummy/20) & $7F
        midiOut.fifoset($B00100 + para)
        colors[i] := para * ( (i+4) & $F ) + $2B060C02
      p2 := dummy

DAT

tvparams      long    0               'status
              long    1               'enable
              long    %001_0000       'pins --- 8..10=[001_0000] , 12..14=[001_0101]
              long    %0000           'mode
              long    0               'screen
              long    0               'colors
              long    x_tiles         'hc
              long    y_tiles         'vc
              long    10              'hx
              long    1               'vx
              long    0               'ho
              long    0               'vo
              long    0               'broadcast
              long    0               'auralcog

vecdef        word    $4000+$2000/3*0, 50, $8000+$2000/3*1+1, 50
              word    $8000+$2000/3*2-1, 50, $8000+$2000/3*0, 50
              word    0

vecdef2       word    $4000+$2000/12*0, 50, $8000+$2000/12*1, 20
              word    $8000+$2000/12*2, 50, $8000+$2000/12*3, 20
              word    $8000+$2000/12*4, 50, $8000+$2000/12*5, 20
              word    $8000+$2000/12*6, 50, $8000+$2000/12*7, 20
              word    $8000+$2000/12*8, 50, $8000+$2000/12*9, 20
              word    $8000+$2000/12*10, 50, $8000+$2000/12*11, 20
              word    $8000+$2000/12*0, 50
              word    0

これで、サウンド入力イベントで画面をとりあえずリフレッシュすること、 照度の変化で「何かが起きる」こと、 それらの情報をMIDI出力すること、を確認した。 MIDI入力で色々なパラメータを与えた方が自由度は大きくなるが、 インスタレーションとしては、センサのイベントでグラフィクスが変化するとともに、 何かのサウンドが発生することが重要と考えて、 これをMIDI出力して、Max/MSPで自在にサウンド生成する、という方針とした。

2008年5月18日(日)

これまでデスクトップ機だったホストを、Sketch03で海外に持ち出してプログラミングするために、 小型のWindowsノートに移行した。

このページ のどこかに写真がさりげに載っている。(^_^;)

2008年5月21日(水)

本日でこの「Propeller日記」はおしまいである。 トラ技の記事の原稿はまだ続いているが、それ以外の状況の進展としては 以下のようなカンジになってきた。 なので、今後は別のWebページで、もっとPropellerを紹介していくことになる。
  • 日本音楽知覚認知学会での発表で紹介(5/24)
  • 音楽情報科学研究会での発表で紹介(5/28)
  • Sketch03で紹介(6/25-27、米国RISD)
  • 音情研・夏シンポで詳細紹介(8/6-8)
  • FIT2008で紹介(9/2-4)
  • RFIDのリーダ製作予定(ゼミの学生作品)
  • オープンキャンパス/MAF2008でのインスタレーション作品に応用(12画面ディスプレイ)
  • A/D変換回路のアイデアあり
  • D/A変換回路のアイデアあり
  • etc (乞う御期待)

たまたま知ったプロセッサであるが、もうしばらくは付き合ってみたいと思う。

→ 4年後の「続・Propeller日記」 に続く (^_^;)