*このパートはH8/300/TinyにMidiを導入するためのノウハウを蓄積するための場所です*
関連項目:

  
H8/3664
  
AKI-H8
  
PallarellPort増設
  
VHDL coding

  前の頁  次の頁
AD周りの環境整備
AD周りの問題は、H8上でMIDI製作を始めた当初から引きずっているが、今回思い切って処理ルーティンを改変することにした。不思議なのは、ADを1chのピックアップに限定している分には問題がないのに、これが数チャンネルに渡ってスキャンを始めた途端に精度が落ち、データのバタつきが発生してしまうことだ。これは、人間の目に見えない領域(スピード、分解能など)で何らかのトラブルが発生していることを示唆する現象だ。

オーディオ的なアプローチで電気工作に携わってきた人間なので、動的な信号を変換するよりも、静的な信号を変換する方が結果的にシステムのアラが見えてしまう現象がとても新鮮だ。まあ、よく考えたら信号の変化が遅い故に不具合が見えてくる、タダそれだけのことなのだが、、、、。

さて、結局3年間いろいろとやってはみたが、ハードウエアの改良で出来るポイントは既にやり尽くした感がある。そこで、視点を変えてWebで発見したあるサイトの意見を読んでみると、MIDI用のコントロールデータのアクイジションタイムは10ms程度が現実的な数値で、これ以上高速化してもゴミデータを吐くだけだという。

確かに、H8のADは高速で、1ch当たり4us程度というから、これは無用に速い。だから、ADのサンプリングを行うタイミングを遅らせるか、もしくはサンプリングポイントを増やしてデータを平均化することが安定した出力を確保するための現実的な方法だろう。実際の工業用途でも、データアクイジション系の処理はそのように行われていると聞く。

ということで、ここからはMIDIデータ取得に有効なADデータの処理アルゴリズムを考えていこう。 

今までの処理ルーティンでは、ADからのデータ取得と、MIDI/Rxへの送信判定ルーティンを analog_check ルーティンとして纏めていたが、各要素をサンプリング/データ蓄積と、送信処理のルーティンに分割する。この方式では、簡単に複数のサンプリングポイントの増減を設定できるが、今回はとりあえずサンプリング・ルーティンを4回行うこととする。実際の結果は実験してみないと判らないが、要求される仕様に合わせてバッファーの段数を調整すれば良いだろう。サンプリング・ルーティンで蓄積されたADデータは、MIDI/Rxへの送信判定を行う際に、それらを纏めた平均値を算出される。その結果を、1サイクル前のデータと照合し、変化が判定されたときのみデータが出力される。

今のところ、メインルーティンの中にサンプリングの為のルーティンを複数挿入しているが、システム全体の遅延が気になった場合は、AD割り込みルーティンを使用して、AD変換に関してはバックグラウンド処理を行うことにしても良いだろう。

先に紹介したサイトでは、SAR方式のADCの代わりに、2つのデジタルポートに渡された RC の充放電時間の差を、ポートのスレッショルド特性を応用してカウントする方式を採用している。これは、ポートを一定期間 “L" の状態にすることで、一旦コンデンサーを放電し、中点が Vcc に接続された VR を通して各ポートに接続された C に再充電を行い、スレッショルド電圧を超えるまでの時間をカウンターで計測、C の充電時間の差を VR の位置情報として出力するというものだ。H8にもこの方式は応用が可能だが、(特に8ch以上のADを組みたい場合。簡単に利用出来るポートは最大8×6あるので、24+8個のVRに余裕で対応出来る)各ポートには動作安定のためのシュミット特性が必要となることに注意しよう。

ここで、実際にAD入力のサンプリングを行うルーティンを紹介しよう。 samp_00 というのがデータバッファーで、この部分に8ポート分のADデータを順次格納していく。今回は samp_00 から samp_03 までの4グループでサンプリングを行っている。実験の結果、送信部の平均化処理だけでは、精度がイマイチなことが解ったので、データ取り込みの段階でもノイズ軽減のための平均化を行うこととした。

  1. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  2. ;;;; sampling the analog inputs
  3. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

  4. sampling_00:

  5.  sub.l er1,er1
  6.  sub.l er2,er2
  7.  sub.l er3,er3 ; AD port counter (r3l)

  8.  mov.l #adda,er2 ; vector addr of adah

  9. _samp00_loop:
  10.  bclr #5,@adcsr
  11.  mov.b r3l,@adcsr ; preset the AD control register
  12.  bset #5,@adcsr ; start convert
  13. _wait_samp00:
  14.  btst #7,@adcsr ; wait for AD complete
  15.  beq _wait_samp00
  16.  bclr #7,@adcsr ; clear the AD complete flag

  17.  mov.b @er2,r1l ;uploading AD data
  18.  extu.w r1

  19.  mov.w r1,e1

  20.  sub.w r1,r1
  21.  mov.b @(samp_00,er3),r1l ;old AD data
  22.  extu.w r1


  23.  add.w r1,e1 ;add all data and div by 2
  24.  sub.w r1,r1 ;clr
  25.  mov.b #2,r1l
  26.  divxu.b r1l,e1 ;r1 contains meaned ad data
  27.  mov.w e1,r1

  28.  mov.b r1l,@(samp_00,er3) ;stock the latest data

  29.  inc.b r3l ; AD port counter
  30.  cmp.b #8,r3l
  31.  beq samp00_end
  32.  add.l #2,er2
  33.  cmp.l #addd,er2 ; vector addr for addh
  34.  ble _samp00_loop
  35.  mov.l #adda,er2 ; vector addr for adah
  36.  bra _samp00_loop
  37. samp00_end

  38. rts
サンプリングを行った後は、得られたデータをMean(平均化)した後、過去に出力したデータとの比較を行う。比較には変化幅のスレッショルド値が設定されているが、判定されるLSBは8ビット精度なので、MIDIデータへの影響は最小限に抑えられている。データはMIDI出力手前で1ビット右にシフトされ、MIDIの規格である7ビットデータに変更される。そのため、出力には同じ値が2発返ってしまうが、最大値と最小値の境界付近で発生する不感帯の発生を、8ビット幅のデータ処理を行うことで回避している。
  1. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  2. ;;;; analog port check
  3. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

  4. analog_check:

  5.  sub.l er1,er1
  6.  sub.l er2,er2
  7.  sub.l er3,er3 ; AD port counter (r3l)

  8. _ad_loop:
  9.  mov.b @(samp_00,er3),r1l ;upload AD data
  10.  extu.w r1
  11.  mov.w r1,e1
  12.  sub.w r1,r1

  13.  mov.b @(samp_01,er3),r2l
  14.  extu.w r2
  15.  mov.w r2,e2
  16.  sub.w r2,r2

  17.  mov.b @(samp_02,er3),r1l
  18.  extu.w r1

  19.  mov.b @(samp_03,er3),r2l
  20.  extu.w r2

  21.  add.w e1,e2 ;add all data and div by 4
  22.  add.w e2,r2
  23.  add.w r2,r1

  24.  sub.w r2,r2

  25.  mov.b #4,r2l
  26.  divxu.b r2l,r1 ;r1 contains meaned ad data

  27.  sub.b r1h,r1h
     
  28.  mov.b @(ad_old,er3),r1h
  29.  mov.b r1l,@(ad_old,er3)

  30.  shlr.b r1l ;right shift 8bit->7bit
  31.  shlr.b r1h ;right shift 8bit->7bit

  32.  cmp.b r1h,r1l ;compare the AD data new,old
  33.  beq _next_ad
  34.  bmi _minus


  35. _plus:
  36.  sub.b r1h,r1l ; r1l-r1h -> r1l
  37.  mov.b #1,r1h
  38.  cmp.b r1h,r1l ; r1l>1 ?
  39.  bge _data_flag_on
  40.  bra _next_ad

  41. _minus:
  42.  sub.b r1l,r1h ; r1h-r1l -> r1h
  43.  mov.b #1,r1l
  44.  cmp.b r1l,r1h ; r1h>1
  45.  bge _data_flag_on
  46.  bra _next_ad

  47. _data_flag_on:
  48.  bset r3l,r0h ; set the AD flag

  49. _next_ad:
  50.  inc.b r3l ; AD port counter
  51.  cmp.b #8,r3l
  52.  beq _send_ad
  53.  bra _ad_loop

  54. _send_ad:
  55.  mov.b #8,r3l
  56. _send_loop:
  57.  dec.b r3l
  58.  btst r3l,r0h
  59.  beq _send_next
  60.  bclr r3l,r0h

  61.  mov.b @(ad_old,er3),r2l
  62.  shlr.b r2l ;right shift 8bit->7bit
  63.  mov.b @(ad_sent,er3),r2h
  64.  cmp.b r2h,r2l ;compare the MIDI data new,old
  65.  beq _send_next

  66. _Data_out:
  67.  mov.b @cc,r0l
  68.  jsr @tx_fifo_set

  69.  mov.b @ccnum,r0l ; cc number read
  70.  cmp.b #67,r0l ; branch cc # is greater  than 67
  71.  blt gt_cc71
  72.  mov.b #111,r0l ; ad/cc number preset to 101
  73.  bra count_ad

  74. gt_cc71:
  75.  mov.b #101,r0l ; ad/cc number preset to 111

  76. count_ad:
  77.  add.b r3l,r0l
  78.  jsr @tx_fifo_set

  79.  mov.b @(ad_old,er3),r0l
  80.  shlr.b r0l ;right shift 8bit->7bit
  81.  mov.b r0l,@(ad_sent,er3)

  82. adValue:
  83.  jsr @tx_fifo_set

  84. _send_next:
  85.  cmp.b #0,r3l
  86.  bne _send_loop

  87.  rts
参考までにサンプリングした出力値を示す。

かなり高速にポーテーション・メーターを操作しても、抜群の追従性を示している。

同じデータが2回返る現象は、データの変化判定をフルスケール8ビットデータのLSBで行っているためだ。データ判定にヒステリシスを持たせた場合、どうしてもデータの最大値と最小値に不感帯が生じてしまう。以前MIDIの仕様に従って7ビットのデータ幅で処理を行っていた時は、データ値の中央付近でオフセットを持たせることで、不感帯発生の問題を回避していたが、この方法では、データの中央付近にどうしても不連続な部分ができてしまう。これは精神衛生上あまり良くないので、データの判定を8ビット精度に変更して、オフセットを廃止している。

ADルーティン以外のデータピックアップの遅れは体感上は殆ど感じられていないので、とりあえずは、デジタルフィルター方式が功を奏したといえるだろう。現在、H8/3052上で安定した動作を確認している。

が、、、後日怪談スイッチに実装して実験したところ、PUSHでER4のデータを待避したことで、受信データとのコンフリクトが発生。PUSH、POPによるレジスタのデータ回避は使用不能なことが発覚した。とはいえ、積分系のルーティンではワードデータの取り回しが必須なので、未使用のE系のレジスタを使用することで問題を回避した。また、AD部では隣接するアナログポートの相互干渉からか、ゴミデータの発生が増加している感があったので、データ判定を7ビット精度に変更し、MIDI出力直前にも重複データを監視するルーティンを追加した。これらの手当を行った結果、ようやく怪談スイッチ上でも、AD部分の正常な動作を確認するに至った。データの重複は一切存在していない。

アナログスイッチを追加することで、最大32ポート位までは、VRをセンシング出来そうだが、CH当たりの実質的な遅延時間の測定が行えていないので、センシング・ルーティンの実装が可能かどうか、今後さらに実験を行って行く予定だ。

オリジナル執筆: 2005_0808
修正加筆: 2005_0818 

追加レポート:2005_0826

その後、3664シリーズに移植を試みるも度重なる失敗を経験。原因は電気系のトラブルなど複合的なモノだったが、プログラム上でAD変換終了フラグを変換終了後にクリアすることで、動作が安定したようだ。
つづく→