続々・Propeller日記(1)

長嶋 洋一


Propeller日記(1)

Propeller日記(2)

Propeller日記(3)

Propeller日記(4)

Propeller日記(5)

続・Propeller日記(1)

続・Propeller日記(2)

続・Propeller日記(3)

続・Propeller日記(4)

続・Propeller日記(5)

続々・Propeller日記(2)

続々・Propeller日記(3)

続々・Propeller日記(4)

2012年12月21日(金)

「P板.com」に、設計した基板の製造GOをかけたのは、 続・Propeller日記(5) の終わり付近、12/10(月)だった。

そしてその後の沈黙期間には、KickStarterでオーダーしていた2件が立て続けにやって来た。 米国からは Blink(1) が、そして英国からは BrightEyes が届いた。 まだあまりライブラリとかは充実していないが、おいおい、これもオリジナル化に向けて遊んでいこう。

・・・と思っていた昨日、教授会が終わった12/20(木)の夕方、遂に以下のメイルが来た。

長嶋洋一 様

いつもお世話になっております。P板.comサポート窓口です。 

下記案件の製造が完了し、本日出荷致しました。

■配達状況は下記URLよりご確認いただけます。
 http://toi.kuronekoyamato.co.jp/cgi-bin/tneko?init
 お問い合わせ伝票番号: 30144******3
 ※ヤマト運輸データシステムに附随する際に、状況更新にお時間が掛かる場合がございます。
出荷・納品方法については下記URLをご参照下さい。
http://www.p-ban.com/information/shipping.html
東北方面へのご配達は、遅れる可能性がございます。
ご迷惑をお掛けいたしますが、何卒、宜しくお願いいたします。

----------------------------------------------------------------
[一括注文番号]:12112600071
[件名]:SUACboard_ver0.5
[出荷予定日]:2012/12/20(木)
[お届け予定日]:2012/12/21(金) (※遠隔地、離島を除く)
[小計]:¥277,705
[消費税(5.0%)]:¥13,885
[注文合計]:¥291,590
[請求書送付方法]:製品同梱
[納品書送付方法]:製品同梱

【共通仕様】
[基板種類]:リジット基板
[構成層数]:4層
[外形寸法]:160.0 mm × 115.0 mm 
[最小パターン幅/間隔]:0.127mm【標準】
[最小穴径/ランド径]:φ0.3/0.6mm【標準】
[レジスト印刷]:両面に塗る
[シルク印刷]:L1面
[板厚]:1.6mm【標準】
[板材]:FR-4【標準】
[銅箔厚み]:内層35μ外層18μ【標準】
[長穴]:なし
[端面スルーホール]:なし
[特性インピーダンス]:指定なし【標準】
[ULマーク]:なし【標準】
- 設計サービス ------------------------------------------------------
【案件情報】
[サービス名]:新規設計
[受付番号]:201211260005D
[設計日数]:11 日
[設計完了予定日]:2012/12/11(火)
【設計仕様】
[CAD選択]:CADLUS X
[ピン数]:999 ピン
[メタルマスクデータ]:なし
[マウントデータ]:なし
【その他仕様】
[パターンの制限配線]:なし
[高周波回路]:なし
[アナログ回路]:あり
[高電圧・高電流を扱う回路]:なし
[シールドに関する処理 ]:なし
[外形が特殊な基板 ]:なし
[部品高さ制限の指示]:なし
[BGA、CSPを搭載する基板]:なし
[シルクに関する特別処理(ロゴ印字など)]:なし
【見積費用】
[設計費用]:¥224,805
[設計サービス合計]:¥224,805
- 製造サービス ------------------------------------------------------
【案件情報】
[サービス名]:(リジット)新規製造
[工場名]:韓国
[受付番号]:201211260066M
[製造日数]:7 日
[製造完了予定日]:2012/12/20(木)
【基板仕様】
[製造コース]:ノーマル
[製造枚数]:20 枚
[表面処理]:半田レベラー(有鉛)【標準】
[レジスト色]:緑【標準】
[シルク印刷色]:白【標準】
[パッドオンビア]:なし
[IVH/ビルドアップ]:なし
[ルーター切り出し面付/種類]:なし【標準】0種
[ミシン目面付/最小幅]:なし【標準】 2.0mm【標準】
[Vカット]:なし【標準】0本
[ジャンプVカット]:なし【標準】0本
[データ面付け編集サービス]:なし
[オープンショートテスト]:あり【推奨】
[ピース×品]:NG【標準】
[DXFデータ変換サービス]:なし
【見積費用】
[イニシャル費用]:¥0
[基板製造費用]:¥52,900
[製造サービス合計]:¥52,900
----------------------------------------------------------------
【お届け先情報】
・・・

ご注文誠にありがとうございました。
商品受け取り後のご意見・感想など下記URL「P板.comの通信簿」にご連絡いただければ幸いです。

今後ともよろしくお願い致します。
そして発送情報を見ると、朝6時半の段階で以下のように、既に浜松に来ている(^_^)。

朝8時半を過ぎたところで発送情報を見ると、以下のように、 SUACのすぐ近くにある、クロネコヤマトの元浜センターを出発した模様である。 ただしSUACに来る順番はいつも遅いので(^_^;)、SUACに届くのは昼頃だろう。

今日は院生の伊熊さんの修了制作のフォローがちょっとあるぐらいなので、 さっそく、基板にICを取り付けていこう。 明日明後日の週末は、音楽情報科学研究会のために東京電機大に行くので、 本格的に遊ぶのは、12/24の祝日になりそうである。

・・・と書いていたが、朝9時半あたりにフト発送情報を見ると、以下のように、 なんと到着していた(^_^)。 素晴らしい。

さっそく事務局に取りに行き、財務室で検収してもらって、研究室に戻って以下のように並べてみた。 通常製造の韓国(急行の場合には台湾、特急の場合には日本)から真空パックで送られてきた、なかなかしっかりしたガラスエポキシの4層基板である。 一瞥しただけで早くも軽いバグ(半固定抵抗の部品穴径が小さかった)を発見したが(^_^;)、これはキチンと指定しなかった僕の問題であり、 次バージョンで改訂するので無問題である。 こう並べてみるとスグにでも取りかかりたいが、明日の出張の準備など雑事があるので、グッと堪えて、まずはお仕事である。

午後に伊熊さんの修了制作の進捗を確認したので、作業の再開は14時過ぎとなった。 せっかく基板が出来ても、部品を搭載しなければ何にもならない。 まずは以下のように、久しぶりにハンダ付けのお店を広げた。

最初にいつものお約束で、四隅にスペーサーを取り付けて立たせた。

そして、覚悟していた久しぶりの作業であるが、100mil(0.1インチ)でなく、その半分の50mil(1.27ミリ)の間隔での、 ミニフラットパッケージのハンダ付けである。 後でちょっと後悔したが(^_^;)、28ピンのA/Dコンバータ : AD7829から取り付けを開始した。 もっと少ないピン数のICから始めれば、だんだん馴れていくのに、後の祭りである。

久しぶりのフラックスの使い方を思い出したところで、今度はビン数が16ピンと少ない74HC138を2個、以下のように取り付けた。

そして、8ポート+バスバッファで計9個の20ピンの74HC245を、以下のように取り付けた。

ミニフラットICの最後は、8ポートで計8個のラッチバッファ、20ピンの74HC574を、以下のように取り付けた。

多数のミニフラットICの載った基板は、以下のように壮観である。ただし、これをあと19枚、作らなくてはならない。(^_^;)

次は105の積層セラミックコンデンサ、パスコンである。 計9個をどこに置くかは「お任せ」としたが、さすが、適切に配置されている。 今回は4層基板で、内部の2層に+5VとGNDがベタで密着しているので、 この程度のパスコンでもノイズ対策としては十分であろう。

次は、ディジタル入力(8ビット×8ポート)のためのプルアップ抵抗(集合抵抗)である。 4.7kΩという数値は、まぁ経験則である(^_^;)。

ここからディスクリート部品である。MIDI出力用のオープンドレインゲートの74HC05と、MIDI入力用のフォトカプラは、 通常の0.1インチのDIPである。ソケットを付けて、壊れた場合には差し替えるようにすることを想定しているが、 今回の実験基板では直付けしてある。

XBeeモジュール用の秋月電子のゲタ基板も搭載する。 このゲタ基板も直付けしたが、ソケットにする事も可能である。

A/Dコンバータの電圧レンジ設定用の半固定抵抗と、PropellerにフォトカプラからのMIDI信号を与えるレベルシフタ用の2SC1815である。 信号ラインに1kΩを直列でもいいのだが、せっかく「Propeller日記」でオリジナルのMIDIドライバと周辺回路を作ったので、 それをそのまま踏襲してある。 周囲にはそれぞれの抵抗とダイオードも取り付けた。

Propellerから2ポートのビデオ信号を出力するための3ビットD/Aのための3本の抵抗が2セット、 そして各マイコンのソケットも取り付けた。

基板の外周には、拡張入出力のコネクタがずらりと並んだ。 今回は、「入力」のポートはピンヘッダ(オス)にして、「出力」のポートはピンソケット(メス)にした。 これは、入力のチェックは、GNDとショートさせることで簡単に出来るから、という程度であり、応用システムでは自由に選択できる。

動作モードに応じて適宜、取り付ける4カ所のジャンパを除いて、これで部品は全て取り付け完了である。 やはり、部品が載ってみると、美しい。(^_^)

Gainerを搭載する場合にはこんな風景となる。ただしXBeeは不要となる。

AKI-H8を搭載する場合にはこんな風景となる。AKI-H8では基板の機能がほぼフル活躍する。

Arduinoを搭載する場合にはこんな風景となる。この写真のArduinoは太いピンなのでちゃんとソケットに刺さっていないが(^_^;)、まぁこんなカンジである。

そして、我がPropellerのPropClipを搭載する場合にはこんな風景となる。Propellerでは基板の機能がほぼフル活躍する。 基板が来て、部品が載ったが、これが正しいかどうかのチェックは、マイコンのソフトを作って実験してみないと確認できない。 Gainerでは基板の機能のごく一部なので無理、そしてArduinoとAKI-H8では、内部FlashEEPROMにいちいち実験のテストプログラムをロードすると、 半導体の書き込み回数制限が気になってくる。 そこで、試行錯誤の実験環境としては、内部SRAMに無制限にプログラムをロード出来るPropellerが、唯一の最適解となる。 つまり、基板の実験では、まさにPropeller三昧となる(^_^)。

ここまで作って写真を撮ったところで、今日はオシマイである。 土日は音楽情報科学研究会(インターカレッジ)のために東京電機大に出張なので、 完全にPropellerから途絶するが、ここまで進めば、次は楽しい楽しい試行錯誤デバッグである。 果たして基板のパターンを切り貼りしないといけないようなバグが出て来るかどうか、それは来週のお楽しみである。

2012年12月24日(月)

さて、新しい週となって、祝日かつクリスマスイブという12/24であるが、そんなの関係ねぇ。 いつものように朝から研究室である。ワイルドだろぉ。(^_^;)

今年のインターカレッジは、インスタが無いので映像2作品という最小規模で、学生引率もなく僕だけで参加した。 土日の音楽情報科学研究会では、以下のように9月にリンツのアルスエレクトロニカで会い、 翌週にスロベニア・リュブリャナのICMCで再会した、英国Leed大学のKia先生とまた再会した、というあたりである。 Leed大学のメディアアート・プロジェクトは音楽だけでなくダンスとのコラボレーションが豊富なので、いずれ機会があれば訪問してみたい、と思った。

溜まったメイル処理など雑事を片付けて、午後になってから、ようやく新基板のチェックに着手した。 まずは、残された4つの部品、ジャンパの部分である。 ジャンパの部品は買っていなかったので、以下のように1列のビンヘッダと、2列ピンソケットをカットして自作してみた。

このジャンパは、続・Propeller日記(5)の中で、以下のように定義していた。
    • SW1 - ArduinoのD0端子をXBee受信にするか/245入力のGにするか
    • SW2 - AKI-H8のシリアル入力をMIDI入力にするか/XBee入力にするか
    • SW3 - MIDI出力をPropellerから出すか/AKI-H8またはArduinoから出すか
    • SW4 - ArduinoのD13端子を245入力のGにするか/574出力のCKにするか
しかし、いざ作ったジャンパを入れようと回路図を眺めてみたが、ここで驚くべき事が判明した。 自分では、ジャンパのピン番号を定義していなかったのである(^_^;)。 つまり、CADソフトの標準部品として「3ピンのジャンパ」という部品を呼び出し、ここに適当に信号を繋いでいたので、 いざ基板のシルクを見ても、中央の信号(2ピン)は分るとして、1ピンと3ピンに、どちらの信号が来ているかは不明なのだった。 さらに、なんだか手描きの時の回路と、CADソフトで出力した回路とで、信号が違うような(=バグ発見(^_^;))気がしてきた。 ここはじっくりとチェックが必要である。

ここは肝心なので、ハンダごてを一旦切って、パソコンに戻り、関係する部分の過去の資料を整理することにした。 まず、 このPDF回路図 は解像度が悪くて読みにくいので、以下のCAD画面を再度、呼び出した。

そして、元となった手描きの回路図は以下である。これも呼び出して、両者を付き合わせるという作業である。

関連する信号は、続・Propeller日記(4)の中で、 以下のように定義していた(抜粋)。
  • AKI-H8
    • P90 - MIDI出力 or XBee出力 (MAX232の11/12pinをcut)
    • P92 - MIDI入力 or XBee入力 (MAX232の11/12pinをcut)
  • Propeller
    • P24 - MIDI入力
    • P25 - MIDI出力
    • P26 - XBee入力
    • P27 - XBee出力
  • Arduino
    • PD0/Rx - (ホスト通信用) / XBee入力 or 汎用入出力・入力245イネーブル(G)
    • PD1/Tx - (ホスト通信用) / MIDI出力 or XBee出力
    • PB5 - 汎用入出力・出力574ラッチパルス(CK) or 入力245イネーブル(G)
これで必要な情報は出揃った。 あとは、上記の信号線ごとに、ピン番号をたどってテスターで確認しつつ、 手描きの回路図をマーカーペンで追いかけて、かつCADソフト上の記述と照合する、 という超アナログな作業である。 世間はクリスマスイブということで、まったく邪魔なメイルも電話も無いので、とても助かる。 毎日届くスパムメイルも、今日はとっても少ない。スパム業者もリア充なのであろうか。(^_^;)

ここから上のようにしばし追いかけて、まず判明してきたのは、 手描き回路図 からCADに入力する段階で、その場で適当に(適切に)翻訳して設計していて、この 手描き回路図 はCAD図面と正しく一致していない、という事実であった。 テキトーだよなぁ(^_^;)。

そして、遂に以下のようにジャンパ関係の情報を整理できた。 幸運にもバグは無かった。 さすが、今朝の「めざましテレビ」で、牡牛座の運勢は1位だった甲斐があるが、 こんなところで運を使ってしまっていいのか。(^_^;)

  • SW1 - ArduinoのD0端子をXBee受信にするか/245入力のGにするか
    • 回路図解析結果
      • 1ピン - XBee受信(Din : 3pin)
      • 2ピン - ArduinoのRX/D0(2pin)
      • 3ピン - 245入力のGを供給する138のG入力
    • 動作モードとジャンパの設定
      • ジャンパ[1-2]ON - ArduinoでXBeeから受信する(speedは19200以下、9600推奨)
      • ジャンパ[2-3]ON - Arduinoで8ビット8ポート・ディジタル入力を行うためのG信号出力
  • SW2 - AKI-H8のシリアル入力をMIDI入力にするか/XBee入力にするか
    • 回路図解析結果
      • 1ピン - XBee受信(Din : 3pin)
      • 2ピン - AKI-H8の[CN1-27]シリアル入力
      • 3ピン - フォトカプラTLP552の出力(6pin)
    • 動作モードとジャンパの設定
      • ジャンパ[1-2]ON - AKI-H8の入力 = XBee
      • ジャンパ[2-3]ON - AKI-H8の入力 = MIDI
  • SW3 - MIDI出力をPropellerから出すか/AKI-H8またはArduinoから出すか
    • 回路図解析結果
      • 1ピン - PropStickのP25(34pin)
      • 2ピン - MIDI出力用74HC05のインバータ入力
      • 3ピン - 「AKI-H8の[CN1-25]シリアル出力」+「ArduinoのTX/D0(1pin)」を受けた74HC05反転出力
    • 動作モードとジャンパの設定
      • ジャンパ[1-2]ON - PropellerからのMIDI出力
      • ジャンパ[2-3]ON - AKI-H8またはArduinoからのMIDI出力(どちらか挿さっている方)
  • SW4 - ArduinoのD13端子を245入力のGにするか/574出力のCKにするか
    • 回路図解析結果
      • 1ピン - 574出力のCKを供給する138のG入力
      • 2ピン - ArduinoのD13(16pin)
      • 3ピン - 245入力のGを供給する138のG入力
    • 動作モードとジャンパの設定
      • ジャンパ[1-2]ON - Arduinoで8ビット8ポート・ディジタル出力を行うためのCK信号出力
      • ジャンパ[2-3]ON - Arduinoで8ビット8ポート・ディジタル入力を行うためのG信号出力
以上から、まずはハードウェア関係のチェックをPropellerで行うので、 Propellerに関係しない「SW1」「SW2」「SW4」は何でもいいので適当に挿して(ジャンパが無くなるといけないのでどちらかに挿す)、 「SW3」だけは、ジャンパ[1-2]ON、に設定した。

次の作業としては、入力・出力それぞれ64ビットずつあるディジタル入出力関係のコネクタに、 ダミーとなるテスト用の何かを作る必要がある。これは今後、基板を手作業量産した際に、チェック治具となる。 また、アナログ入力用の治具も24チャンネル分、必要である。 しかし、明日25日には、某総決起集会というイベントがあり、お休み(振休)なのである。 そこで、今日はここまで、とした。 まぁ休日としては、ソコソコ進んだだけでOKだろう。

2012年12月27日(木)

一昨日の12/25(火)には今年最後の歌い納めでカラオケマラソン9時間を完走したので、何もナシ。 昨日の12/26(水)は、「メディアアーツ論」と「サウンドデザイン演習」の講義ページを来年の第13回に向けて改訂し、 さらに ワークショップの参加募集ページ を作って募集を開始したり、3月の情報処理学会全国大会の原稿を完成させて学会に送ったりした。 業者が以下のようにマイクロSDカードを納品してきたので、 こっちの続き もやりたいが、ここは基板のチェックが優先であるので、グッと堪えた。

「サンダーバード」の作者が亡くなった、というニュースが届いて、午前中はちょっとYouTubeを散策していたので(^_^;)、 作業再開は午後となった。 まずは以下のように、パスコンのGND側にテストクリップを取り付けて、 さらにスイッチングACアダプタを取り付けた。 電源コネクタを使わないのも、電源スイッチを使わないのも、いつもの事である。 組み込み機器に、電源スイッチは不要である(基本的に連続動作しっ放し)というのが僕のポリシーである。 リセットの際には電源を抜けばいいのだ。

さて、ここからであるが、Propellerを使うこともあり、まずは「ビデオ出力」と「MIDI入出力」から行うことにした。 既に自前のライブラリとかが完備しているのと、これらの動作が確保できれば、いろいろな実験のモニタとしては十分に強力だからである。 以下のように、2系統のビデオケーブルと2本(送信/受信)のMIDIケーブルを自作して取り付けた。

ここでハンダごてをいったん切り、パソコンデスクに移動して、以下のようにお店を広げた。 Propellerでは既にやっているが、ビデオモニタを2台並べて、その両方に別々の表示出力を同時に行う、 それもビデオ信号をPropeller内部の8個のCog(CPU)のうち2個ずつを使ってソフトウェア的に生成する、 なんてのは、他のマイコンでは逆立ちしたって不可能なのである。 まさに「Propeller日記」の本領発揮である。(^_^)

さて、Propellerのビデオ出力のポートは・・・と過去に遡って探してみると、なんと 続・Propeller日記(4) の最後のあたりで、以下のように定義していた。 そこからもう、ずいぶん遠くに来たもんである。(^_^;)
  • AKI-H8
  • Propeller
    • P0-P2 - Video出力(1)
    • P3 - (reserved)
    • P4-P6 - Video出力(2)
    • P7 - (reserved)
    • P8-P15 - 汎用入出力拡張バスライン
    • P16-P18 - 汎用入出力アドレス(A0-A2)
    • P19 - 汎用入出力・出力574ラッチパルス(CK)
    • P20 - 汎用入出力・入力245イネーブル(G)
    • P21 - 汎用入出力・AD7829イネーブル[1](CS/RD)
    • P22 - 汎用入出力・AD7829イネーブル[2](CS/RD)
    • P23 - 汎用入出力・AD7829変換開始(CONVST)
    • P24-P25 - MIDI入出力
    • P26-P27 - XBee入出力
    • P28-P31 - USB通信/Flashメモリ用に予約
  • Arduino
  • Gainer
上の定義から、2系統のビデオ出力のベースピンは「0」と「4」である。 そこで、PropQuickStartの時のPropellerプログラムを簡単にして、以下のように2系統出力のプログラムを作ってみると、 なんとエラーが出た(^_^;)。グラフィックライブラリを2系統も持つと、Propeller内部のRAMが不足するらしい。
CON
  _clkmode = xtal1 + pll16x
  _xinfreq = 5_000_000

OBJ
  Num : "E_Numbers02"
  TV1 : "E_TV_Terminal02"
  TV2 : "E_TV_Terminal02"

PUB main | dummy, data, sel
  Num.Init           { Num.Init MUST be called before first object use. }
  TV1.Start1(0)
  TV1.Start2
  TV2.Start1(4)
  TV2.Start2
  TV1.out(1)
  TV2.out(2)

  repeat
    dummy := (dummy+1) & 255
    sel := (sel+1) & 7
    TV1.out(13)
    TV1.Str(Num.ToStr(dummy, Num#DEC))
    TV1.Str(Num.ToStr(data, Num#HEX3))
    TV2.out(13)
    TV2.Str(Num.ToStr(dummy, Num#DEC))
    TV2.Str(Num.ToStr(data, Num#HEX3))
    if sel == 0
      waitcnt(10000000+cnt)
      TV1.out(0)
      TV2.out(0)

念のために、上のプログラムでビデオ1系統だけにして、もう片方をコメントアウトすると、両方ともちゃんとビデオは出た。 つまり、ハードウェアはOKである。 そこで、巨大な「E_Graphics02.spin」から、テキスト表示以外のグラフィック機能を削った以下の「E_Graphics03.spin」を作り、 呼び出し側の「E_TV_Terminal02.spin」を「E_TV_Terminal03.spin」と改訂してみると、 以下のように、見事に2画面で表示できた。 ただし残りのメモリはギリギリである(^_^;)。

ここからあれこれ、グラフィックライブラリを試行錯誤的に削ってはコンパイルしたが、 どうやっても変数エリアが小さくならない。 やはり、膨大なフォントテーブルをメモリに展開する、というのをダブルで、というのは苦しいようである。 考えてみれば、 電子十二影坊 (Dodeca Propeller) の時にも、12画面の表示に12個のPropeller、あと制御用に1個のPropellerを使ったのだから、 「1個のPropellerで2画面」というのは、ごく最初にテストした(他の機能を使わない)時だけだったのだ。

そこで作戦変更して、1画面だけをテキスト表示(16進数変換なども対応)専用に、 もう1画面はテキスト(フォント)の部分をばっさり削ってグラフィクス専用に、 という構成を試してみた。 昔のライブラリをあれこれ引っ張り出してリネームなどした結果、以下のように、テキスト表示をコメントアウトすると、 余裕でグラフィック表示するものの、両方を生かすと、どうしてもメモリ不足でコンパイルエラーが解決できなかった。 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
  x_origin = 128
  y_origin = 96
  paramcount = 14
  bitmap_base = $2000
  display_base = $5000
VAR
  long  tv_status, tv_enable, tv_pins, tv_mode, tv_screen, tv_colors, tv_hc, tv_vc
  long  tv_hx, tv_vx, tv_ho, tv_vo, tv_broadcast, tv_auralcog,colors[64]
  word  screen[x_tiles * y_tiles]
OBJ
'  Num : "E_Numbers02"
'  TV1 : "E_TV_Terminal03"
  gr2 : "E_Graphics04"
  tv2 : "E_TV02"
PUB main | i, j, k, para, dummy, data
'  Num.Init           { Num.Init MUST be called before first object use. }
'  TV1.Start1(0)
'  TV1.Start2
  longmove(@tv_status, @tvparams, 14)
  tv_screen := @screen
  tv_colors := @colors
  tv2.start(@tv_status)
  gr2.setup(x_tiles, y_tiles, x_origin, y_origin, bitmap_base)
  repeat i from 0 to tv_hc - 1
    repeat j from 0 to tv_vc - 1
      screen[j*tv_hc+i] := display_base>>6+j+i*tv_vc+((j&$3F)<<10)
  repeat i from 0 to 63
    colors[i] := $00001010 * (i+4) & $F + $2B060C02    { 11060C02 }
  dummy := 0
  data := 0
  repeat
    dummy++
    if dummy > 1000
      dummy := 0
      data := (data+1) & 255
'      TV1.out(data//3+1)
'      TV1.Str(Num.ToStr(data, Num#HEX3))
    gr2.clear
    gr2.colorwidth(1,1)
    repeat i from 1 to 20
      gr2.vec(para*2, para*2, (k & $7F) << 3 + i << 5, k << 6 + i << 8, @vecdef)
    gr2.copy(display_base)
    k++
DAT
tvparams      long    0               'status
              long    1               'enable
              long    %000_0101       'pins --- 0...2=[000_0000] , 4...6=[000_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

だいぶPropellerの勘を取り戻してきたが、今日はこんなところである。 明日にはMIDIと絡めて確認して、入出力ポートの拡張の確認へと進んでいきたいところである。

2012年12月28日(金)

今日は年末最終の週末で、SUAC事務局とかは「仕事納め」の日である。 メディア造形学科では、1回生向けのアニメーション技法の集中講義も行われている筈である。 今年最終ということで事務局に行ってみると、なんと以下のように、発注していたRaspberry Piが届いていた。

気付いてみればRaspberry Piのボードだけ発注して、OSの入ったSDメモリカードは発注し忘れたので(^_^;)、 SDカードを別途に発注してUnixベースでオリジナルを複製するか、ダウンロードする必要がある。 これこれ とともに、Raspberry Piも色々と遊びたいグッズである。 しかし、ここはグッと堪えて、まずはPropellerである。

さて、昨日のPropellerであるが、ビデオ出力2系統というのはメモリの制限から苦しい、というところまでだった。 そこで過去の記録を発掘してみると、昨日あれこれ苦しんだことを、 Propeller日記(5) でやっていた、と判明した。 マイコン屋は特定のマイコンに固執することなくどんどん忘れていい、 必要な時にマニュアルを調べて使えればいい(頭はROMでなくRAMに)、 というのが鉄則であるが、既にまったく忘れていたのだった。(^_^;)

しかし今回は、新基板でPropellerの周辺拡張能力が拡大しているので、やはりビデオ2系統でシステムの情報をグラフィック表示したい。 テキストは必要条件ではない。データをMaxに転送してホストPCでいくらでも表示できる。 そこで、過去の到達点を確認して、MIDI入出力の組み込みとともに、利用できるようにビデオ出力を整理することにした。 スタートラインは Propeller日記(5) の最後にあった「proto005.spin」であり、これを「board_004.spin」に盛り込むとともに、 ビデオ出力ライブラリ「E_TV02.spin」はそのまま使い、 グラフィック描画ライブラリ「E_Graphics03.spin」を改訂した「E_Graphics05.spin」として、 今後、必要に応じて不要な描画処理をどんどん削除することとした。 MIDI回りでは、 Propeller日記(2) で完成していた「MidiOut01.spin」と「MidiIn03.spin」を。そのまま使うことにした。

そして午後イチで出来たのが、以下のようなものである。 「E_Graphics05.spin」はテキスト描画とスプライト描画をカットして軽くして、2画面のグラフィック表示とともに、 MIDI受信とMIDI送信を同時に行っている。 2画面のために画面のチラつきを避けるためのダブルバッファを省略しているので、 メインループのたびに画面クリアをするとチラつくので、棒グラフの描画の際に、グラフ上方の余白を黒く塗っている。 つまりグラフィックは、油絵のように、全て「上塗り」を無限に続けている。 処理能力のテストを兼ねて、ホストのMaxからは10系統の別々のメトロ・カウンタから値を100msec程度で、 つまり全体としては10msec間隔ほどでデータを送り続けていて、さらにPropellerは、いちいちその受け取ったMIDIデータを返送して、 Max画面で確認している。 このくらいの動作でへこたれていては困るのだ。

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 = 0
  y_origin = 0
  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]

OBJ
  midiIn : "MidiIn03"
  midiOut : "MidiOut01"
  tv[2] : "E_TV02"
  gr[2] : "E_Graphics04"

PUB start | i, dx, dy, dummy
  midiIn.start(24)
  midiOut.start(25)
  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)
  repeat i from 0 to 63
    colors[i] := $00001010 * ( (i+4) & $F ) + $2B060C02
  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)
  gr[0].clear
  gr[1].clear

  repeat
    dummy := midiIn.event
    if dummy <> -1
      midiOut.fifoset(dummy)
      if (dummy & $FFFF00) == $B00000
        display(0, dummy & $00007F)
      elseif (dummy & $FFFF00) == $B00100
        display(1, dummy & $00007F)
      elseif (dummy & $FFFF00) == $B00200
        display(2, dummy & $00007F)
      elseif (dummy & $FFFF00) == $B00300
        display(3, dummy & $00007F)
      elseif (dummy & $FFFF00) == $B00400
        display(4, dummy & $00007F)
      elseif (dummy & $FFFF00) == $B00500
        display(5, dummy & $00007F)
      elseif (dummy & $FFFF00) == $B00600
        display(6, dummy & $00007F)
      elseif (dummy & $FFFF00) == $B00700
        display(7, dummy & $00007F)
      elseif (dummy & $FFFF00) == $B00800
        display(8, dummy & $00007F)
      elseif (dummy & $FFFF00) == $B00900
        display(9, dummy & $00007F)

PUB display(num, data)
  gr[0].colorwidth(num//3+1,0)
  gr[0].box(num*25+5, 0, 21, data*192/128)
  gr[0].colorwidth(0,0)
  gr[0].box(num*25+5, data*192/128+1, 21, data*191)
  gr[1].colorwidth((num+1)//3+1,0)
  gr[1].box(num*25+5, 0, 21, data*192/128)
  gr[1].colorwidth(0,0)
  gr[1].box(num*25+5, data*192/128+1, 21, data*191)

DAT
tvparams      long    0               'status
              long    1               'enable
              long    %000_0000       'pins --- 0...2=[000_0000] , 4...6=[000_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

YouTube
上のようなトラフィックでのMIDI双方向通信と2画面グラフィックが、Propellerで出来ることを確認したので、 もう一つ、Max/MSP/jitterとの連携を実験してみた。 不鮮明で詳細不明のムービーがネットに落ちていたので、これを再生するjitterバッチからサウンドを取り出し、 10バンドのバンドパスフィルタを並べて、要するにサウンドの周波数成分に対応してライブで表示する、 というのを、Propellerの方のプログラムをそのままにして、Max側で作ってみたのが以下である(所要20分ほど)。 メディア造形学科の学生であれば、このくらいのパッチはサクサクと出来る、というのを再認識して、 いろいろと活用して欲しいものである。

YouTube
上記のMaxパッチでは、10バンドのイコライザの出力オーディオグラフobjectの演算周期をdefaultの50msecとしている。 従って、10バンド分のデータが一斉に出てくるので、平均のデータ密度は5msecほどである。 他に何も仕事をしなくても、このトラフィックのMIDIを受けるだけで、標準のツールのC言語でプログラミングしたArduinoは、 MIDIデータを受け損ねてとりこぼす。「ArduinoでMIDI受信が使えない」という所以である。 また、AKI-H8であればMIDI受信は楽勝だが、外部にビデオ信号生成のハードウェアを別に持たないと、 同時にこのようなグラフィック表示は無理である。 その意味で、シリアル通信もUARTナシにソフトで送受信し、ビデオ信号もソフト的に生成しつつ、 これだけの処理を行うPropellerは、流石なのである。(^_^)

「区切り」感から、今日はこのあたり、というカンジである。 今のところ、致命的なバグは出ていないが、まだ油断せずにチェックを続けていこう。

2012年12月29日(土)

いよいよ今年の最終日である。 この日は毎年好例のバックアップの日なので、出張用のMacBookAirに専用のHDDを用意して、 TimeMachineでバックアップを走らせた。 過去にはお仕事パソコンのHDDもこの日にバックアップしたが、2年ほど前から、 常時、500GB HDDを繋いでTimeMachineを走らせているので、こちらはとりたてて何もしない。 そしてその合間に、ちょっとだけ、フト夜中に気になった点を確認することにした。 それは、遠い昔に、 Propeller日記(1) の真ん中あたりでやった、「cognew()」コマンドである。

Propellerは8つのCPU(Cogs)がハードウェア的に並列動作する並列処理プロセッサである。 普通の組み込み用途では、その8つを全部使うというよりは、適当に余っている状況がほとんどである。 しかし昨日の例では、「シリアル通信(MIDI)をUARTナシにソフトで送受信し、2系統のビデオ信号もソフト的に生成」という荒技を実現した。 これはもちろん、普通のマイコンでは逆立ちしても不可能であるが、その時に8個のCogのうち、いくつまで稼働していたのか、 とフト、夜中に目覚めた時に気になってしまったのである(^_^;)。

そこで、あらためて Propeller日記(1) に自分が書いた解説を読み直して(ほとんど忘れていた(^_^;))、 昨日のプログラムでいくつのCogsが呼び出されていたのか、これは今後、さらにいくつのCogsの仕事まで、 追加して同時に走らせることが出来るのか、という目安として確認したい、と思い立ったのである。 通常のマイコンと違い、Propellerではいくつタスクを並列処理させても、ハードウェア並列処理のために、 他のタスクの処理能力が下がらない、というのが「売り」なのである。

実験は、昨日の最後に作ったPropellerプログラム「board_004.spin」を改編せず、 これをコピーしてrenameした「board_005.spin」で実験することにした。 同時に、「board_004.spin」とペアとなったMaxパッチ「SUACboard_test002.maxpat」も改編せず、 これをコピーしてrenameした「SUACboard_test003.maxpat」で実験し、MIDI情報として追加で「現在使用中のCogs数(残りCogs数)」を得る、 という方針にした。

ちなみに、この実験方針にはもう一つの理由がある。 昨日、素材として使った「ネットに落ちていた不鮮明で詳細不明のムービー」であるが、 どこかで聞いたことがあるような気がしないでも無かったので、 YouTubeに上げて、もしかして著作権で叱られるのでは(^_^;)、という危惧があった。 しかし、今日パソコンを立ち上げてみると、別にYouTubeから文句のメイルは届いていなかった。 念のためYouTubeのアップロードページにログインしてみると、 この半年で以下のように既に295本もアップしていたと判明したが、昨日のムービーはOKのようである。

上のアップロード動画リストの中に「第三者のコンテンツと一致しました」とあるのは、全てYouTubeから警告が来たものである。 YouTubeの著作権チェックは完全自動の音響データ検索らしく、早い場合にはアップロードして1分以内にログイン画面内に警告が出て、 ログアウトしている場合には警告メイルが来る。 そして、タリスの演奏のように「問題ないぞ」と申し立てをメイルすると。後日、何もなかったようにクレームが消えることもあるが、 「おっしゃる通りです」と返答すると、ケースバイケースだが、「冒頭に数秒のCMが入る」「世界の中で特定地域では再生できない」などの対応となる。 昨日の動画は、やはり、画像が不鮮明なのと、音楽がパソコンに繋いだ小型スピーカから室内に出ているだけで、 さらに音楽が不自然にループしていたからだろうか。(^_^;)

さて、実験のためのテキストは Propeller日記(1) の「2008年3月6日(木)」あたり、そして Propeller日記(2) の「2008年3月11日(火)」あたりである。 まず、以下のように、「midiOut」だけが生きているようにPropellerプログラムの他の部分をコメントアウトして、 走らせてみると、ちゃんとMax側で「MIDI 1チャンネルのプログラムチェンジ=128」と受信できることを確認した。 細い線であるが、これでPropellerからの情報を受け取れるわけである。

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 = 0
  y_origin = 0
  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]

OBJ
  midiIn : "MidiIn03"
  midiOut : "MidiOut01"
  tv[2] : "E_TV02"
  gr[2] : "E_Graphics04"

PUB start | i, dx, dy, dummy
  midiOut.start(25)
  midiOut.fifoset($C0007F)

{
  midiIn.start(24)
  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)
  repeat i from 0 to 63
    colors[i] := $00001010 * ( (i+4) & $F ) + $2B060C02
  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)
  gr[0].clear
  gr[1].clear
}

  repeat
{
    dummy := midiIn.event
    if dummy <> -1
      midiOut.fifoset(dummy)
      if (dummy & $FFFF00) == $B00000
        display(0, dummy & $00007F)
      elseif (dummy & $FFFF00) == $B00100
        display(1, dummy & $00007F)
      elseif (dummy & $FFFF00) == $B00200
        display(2, dummy & $00007F)
      elseif (dummy & $FFFF00) == $B00300
        display(3, dummy & $00007F)
      elseif (dummy & $FFFF00) == $B00400
        display(4, dummy & $00007F)
      elseif (dummy & $FFFF00) == $B00500
        display(5, dummy & $00007F)
      elseif (dummy & $FFFF00) == $B00600
        display(6, dummy & $00007F)
      elseif (dummy & $FFFF00) == $B00700
        display(7, dummy & $00007F)
      elseif (dummy & $FFFF00) == $B00800
        display(8, dummy & $00007F)
      elseif (dummy & $FFFF00) == $B00900
        display(9, dummy & $00007F)
}

PUB display(num, data)
{
  gr[0].colorwidth(num//3+1,0)
  gr[0].box(num*25+5, 0, 21, data*192/128)
  gr[0].colorwidth(0,0)
  gr[0].box(num*25+5, data*192/128+1, 21, data*191)
  gr[1].colorwidth((num+1)//3+1,0)
  gr[1].box(num*25+5, 0, 21, data*192/128)
  gr[1].colorwidth(0,0)
  gr[1].box(num*25+5, data*192/128+1, 21, data*191)
}

DAT
tvparams      long    0               'status
              long    1               'enable
              long    %000_0000       'pins --- 0...2=[000_0000] , 4...6=[000_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

ここで、唯一、起動されている「midiOut.start(25)」の呼ばれているMIDI出力ライブラリ「MidiOut01.spin」の冒頭部分を見ると、
PUB start(_midiPin) : status
  midiPin := _midiPin
  tx_top := @tx_Head
  tx_end := @tx_Tail
  tx_fifo := @tx_Buff
  bitticks := clkfreq / 31_250
  longfill(@tx_Head,66,0)
  status := cognew(@asm_entry, 0)
つまり、「cognew(@asm_entry, 0)」の結果が帰ってくるのである。 そこで、プログラムの冒頭部分を以下のように変えてMIDIからこの値を見てみると、「2」と確認できた。
PUB start | i, dx, dy, dummy
  dummy := midiOut.start(25)
  midiOut.fifoset($C00000 + dummy & $00007F)
・・・

Maxで表示された「2」は、MIDIのプログラムチェンジのお約束でインクリメントされているので、 MIDIで実際に返ってきた値は2ではなくて「1」である。 つまり、defaultのCog(0)に続いて、このPropellerプログラムでMIDI送信まで行う場合には、 Cog(1)までの2個のCogが使われている、と確認できた。

次はMIDI受信である。 MIDI送信ライブラリとまったく同様に、startに対して「cognew(@asm_entry, 0)」の結果を返すので、 プログラムの冒頭部分を以下のように変えてMIDIからこの値を見てみると、「3」と確認できた。

PUB start | i, dx, dy, dummy
  midiOut.start(25)
  dummy := midiIn.start(24)
  midiOut.fifoset($C00000 + dummy & $00007F)
・・・

Maxで表示された「3」から、MIDIで実際に返ってきた値は「2」である。 予想通りに、defaultのCog(0)に続いて、このPropellerプログラムでMIDI送信/受信まで行う場合には、 Cog(2)までの3個のCogが使われている、と確認できた。 グラフィック(ビデオ出力)で2個もCogも使うのは、1個のCogは刻々とビデオ信号のタイミングに合わせて、 画面内の画素ごとに外部の簡易D/Aでビデオ信号にするためである。 もう1個のCogは、テキストのフォントテーブルを参照したり、 ドット・ライン・三角形・矩形(二つの三角形として)・円弧・楕円などのグラフィック要素を計算して、 これを画素データに展開するための仕事を担当しているのである。

さて、問題はグラフィック回りである。 こちらはMIDIのように簡単ではない。「E_TV02.spin」と「E_Graphics04.spin」の両方を必要とするからである。 まず「E_TV02.spin」については、以下のように、値を返すことが分る。

PUB start(tvptr)
  return cognew(@entry, tvptr)
しかし「E_Graphics04.spin」では、以下のように値を返さない。
PUB setup(x_tiles, y_tiles, x_origin, y_origin, base_ptr) | bases_ptr, slices_ptr
  cognew(@loop, @command)
  setcommand(_loop, 0)                                  'make sure last command finished
  repeat bases_ptr from 0 to x_tiles - 1 <# 31          'write bases
    bases[bases_ptr] := base_ptr + bases_ptr * y_tiles << 6
  y_tiles <<= 4                                         'adjust arguments and do setup command
  y_origin := y_tiles - y_origin - 1
  bases_ptr := @bases
  slices_ptr := @slices
  setcommand(_setup, @x_tiles)
  bitmap_base := base_ptr                               'retain high-level bitmap data
  bitmap_longs := x_tiles * y_tiles
そして、この2つのライブラリの呼び出される順番も不確実だし、実験のためにあまりライブラリに手を加えたくない。 そこで考えたのが、2画面のうちまずは1画面分のグラフィックを起動して、 その後にMIDI受信を初期化して、その時のCogの数を見てみる、という手である。 プログラムの冒頭部分を以下のように変えてMIDIからこの値を見てみると、「5」となった。 もちろん、ムービーの再生に対応して10バンドのグライコの情報はMIDI送信され、 Propellerシステムはこれを受けてグラフィック生成し、さらにこのデータをMIDIで返送している。
PUB start | i, dx, dy, dummy
  midiOut.start(25)

  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)
  repeat i from 0 to 63
    colors[i] := $00001010 * ( (i+4) & $F ) + $2B060C02
  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)
  gr[0].clear
'  gr[1].clear

  dummy := midiIn.start(24)
  midiOut.fifoset($C00000 + dummy & $00007F)

  repeat
    dummy := midiIn.event
    if dummy <> -1
      midiOut.fifoset(dummy)
      if (dummy & $FFFF00) == $B00000
        display(0, dummy & $00007F)
      elseif (dummy & $FFFF00) == $B00100
        display(1, dummy & $00007F)
      elseif (dummy & $FFFF00) == $B00200
        display(2, dummy & $00007F)
      elseif (dummy & $FFFF00) == $B00300
        display(3, dummy & $00007F)
      elseif (dummy & $FFFF00) == $B00400
        display(4, dummy & $00007F)
      elseif (dummy & $FFFF00) == $B00500
        display(5, dummy & $00007F)
      elseif (dummy & $FFFF00) == $B00600
        display(6, dummy & $00007F)
      elseif (dummy & $FFFF00) == $B00700
        display(7, dummy & $00007F)
      elseif (dummy & $FFFF00) == $B00800
        display(8, dummy & $00007F)
      elseif (dummy & $FFFF00) == $B00900
        display(9, dummy & $00007F)

PUB display(num, data)
  gr[0].colorwidth(num//3+1,0)
  gr[0].box(num*25+5, 0, 21, data*192/128)
  gr[0].colorwidth(0,0)
  gr[0].box(num*25+5, data*192/128+1, 21, data*191)
{
  gr[1].colorwidth((num+1)//3+1,0)
  gr[1].box(num*25+5, 0, 21, data*192/128)
  gr[1].colorwidth(0,0)
  gr[1].box(num*25+5, data*192/128+1, 21, data*191)
}

Maxで表示された「5」から、MIDIで実際に返ってきた値は「4」である。 つまり、このPropellerプログラムでMIDI送信/受信まで行ってCog(2)までの3個のCogが使われ、 さらにグラフィック表示1系統で、あと2個、合計5個のCogが使われている、と確認できた。

ここまで来れば結果はほぼ見える(^_^)。 プログラムの冒頭部分を以下のように変えてMIDIからこの値を見てみると、「7」となった。 この動作は昨日のプログラムと同じである。

OBJ
  midiIn : "MidiIn03"
  midiOut : "MidiOut01"
  tv[2] : "E_TV02"
  gr[2] : "E_Graphics04"

PUB start | i, dx, dy, dummy
  midiOut.start(25)
  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)
  repeat i from 0 to 63
    colors[i] := $00001010 * ( (i+4) & $F ) + $2B060C02
  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)
  gr[0].clear
  gr[1].clear

  dummy := midiIn.start(24)
  midiOut.fifoset($C00000 + dummy & $00007F)

  repeat
    dummy := midiIn.event
    if dummy <> -1
      midiOut.fifoset(dummy)
      if (dummy & $FFFF00) == $B00000
        display(0, dummy & $00007F)
      elseif (dummy & $FFFF00) == $B00100
        display(1, dummy & $00007F)
      elseif (dummy & $FFFF00) == $B00200
        display(2, dummy & $00007F)
      elseif (dummy & $FFFF00) == $B00300
        display(3, dummy & $00007F)
      elseif (dummy & $FFFF00) == $B00400
        display(4, dummy & $00007F)
      elseif (dummy & $FFFF00) == $B00500
        display(5, dummy & $00007F)
      elseif (dummy & $FFFF00) == $B00600
        display(6, dummy & $00007F)
      elseif (dummy & $FFFF00) == $B00700
        display(7, dummy & $00007F)
      elseif (dummy & $FFFF00) == $B00800
        display(8, dummy & $00007F)
      elseif (dummy & $FFFF00) == $B00900
        display(9, dummy & $00007F)

PUB display(num, data)
  gr[0].colorwidth(num//3+1,0)
  gr[0].box(num*25+5, 0, 21, data*192/128)
  gr[0].colorwidth(0,0)
  gr[0].box(num*25+5, data*192/128+1, 21, data*191)
  gr[1].colorwidth((num+1)//3+1,0)
  gr[1].box(num*25+5, 0, 21, data*192/128)
  gr[1].colorwidth(0,0)
  gr[1].box(num*25+5, data*192/128+1, 21, data*191)

これで全てが明確になった。 ここまでのシステムでは、以下のようなCogの分配となっていることになり、 MIDI送受信に2画面グラフィックを走らせた場合、あと追加できるCogは1個である。
  • メイン動作のためにdefaultのCog(0)
  • MIDI送信ライブラリのためにCog1個
  • MIDI受信ライブラリのためにCog1個
  • ビデオ出力グラフィック(1)のためにCog2個
  • ビデオ出力グラフィック(2)のためにCog2個
この基板では、AKI-H8ではMIDIとXBeeとは排他的に選ぶが(使えるシリアルポートは1つなので)、 PropellerではMIDIとXBeeとを、原理的には同時に、そして送受信とも処理可能である。 今日、確認できたのは、MIDIの送信、受信にそれぞれ追加のCogは1個でいいので、 同時にMIDI送受信とXBee送受信を行うと、通信に4個とメイン1個の計5個のCogが必要となる、という事である。 これでも、なかなかに強力である。

組み込み機器では、わざわざ2系統のビデオ出力を同時に使うこともないので、今回の実験は、 まずまず安心と納得の結果となった。 これで心おきなく、年末年始はメイルもチェックせず、だらだらと過ごすことが出来そうである。(^_^)

2013年1月4日(金)

ネットから途絶され、本当にだらだらと過ごした年末年始も明けて、 SUAC事務局も仕事始めとなった1月4日、11階の1106研究室の席からブラインドの隙間を開けると、 窓越しにもくっきりと、以下のように富士山が奇麗に見えていた。 SUAC開学当初(2000-2002年)頃は、冬場は毎日のように富士山が見えていたのに、 毎年、確実に空気が霞んできて見えなくなってきて、今では月に何回か見えるという程度である。 中国から遠路、飛散してくるスモッグは半端ない。

さて、新基板「SUAC board ver0.5」のチェックの続き、もちろんホストマイコンの主役はPropellerである(^_^)。 12/29にはMIDI入出力と2系統ビデオ描画(グラフィックのみ、テキストはメモリの関係で省略)までチェックした。 合わせてCog数も確認し、そこそこキツいトラフィックの動作もPropellerは楽々とこなす、と再確認したところまでだった。 今日はまず、XBeeの部分もチェックしてから、その次に周辺機能拡張のパラレルポートに進むことにしよう。

基板の回路設計では当たり前のように並べていたXBeeであるが、いざ使おうとすると、もう詳細は奇麗に忘れていた(^_^;)。 まずは過去の資料探しである。 過去のページを見ると、 2012年8月28日 には、渡欧に持参するOLEDモジュールにXBeeを取り付けていた。 その中のリンクから辿ると、 2012年6月21日 に、「初めてのXBee」ということで試していた。 これは、 ここの最後 にあるように、 留学生のイー君の改造三味線に内蔵して、センサ情報をMaxに飛ばしたものである。 そして、Maxを使っての動作確認のために、 2012年8月29日 で、XBee通信のための「XBee_In.spin」と「XBee_Out.spin」を開発していた。 そして渡欧から帰国して、伊熊さんの修了制作作品のためのシステムとして、 2012年9月29日2012年10月18日 に、Propellerをホストとして完成していた。

上の2つの例はほとんど同じようで、実はマスタークロックもXBeeの通信速度も違っている。 伊熊さんのシステムでは、作品の性格から反応速度は厳しくないので、最初の実験( Sketching2012 に持参)と同じ19200bpsとしていたが、 渡欧に持参したOLED版では38400bpsにしてみた。 今後、「SUAC board ver0.5」でXBeeを使うテンプレートとして新しく作るためには、 MIDIをやや上回る(Arduinoでは最高速度の)38400bpsとしたいので、XBeeドライバも新しいものにする必要がある。 そのためにまず、「38400で素通し通信」という設定を書き込んだ「XBeeペア」という部品を、 今後の実験のために、ここでいくつも作っておく事にした。

設定を書き込んだXBeeの動作を確認し、あわせてXBee回りを思い出すために、 1ペアだけ残っている(もう1ペアはイー君システムの改造三味線に内蔵)Arduino-XBeeモジュールと、 XBee受信モジュールを持ってきて、対応するチェック用Maxパッチも発掘してみた。 過去のパッチはXBeeとダブルで通信していたので、以下のようにシングルに改訂して、 無事に、Arduinoに繋いだテスト用のジョイスティック2本とスライダーとCO2センサの情報を獲得できた。 このパッチは、逆にMax側から、毎秒10データずつ変化させるデータをArduinoに送り、ArduinoからはXBee経由で返送しているので、 これで送受信の両方のチェックが出来る。

完全に忘却していたが、めげずにWindowsパソコンを起動して、以下のように個々のXBeeにマーキングしつつ、 まずは新しいXBeeペアを38400に設定してファームウェアを書き込んだ。 ここで、XBeeを載せているArduinoの方のファームウェアも38400にしなければならない(^_^;)、 と気付いたり色々して、無事に新しいXBeeペアを設定して、Max側で38400に改訂した新しいパッチと双方向通信が出来た。 ツール一式は これ である。

そして、手元のXBeeを2ペア、設定したところで、突然に壁に突き当たった。 ここまで使ってきたXBeeは、シリーズ「S1」ばかりだったが、かつて秋月電子から購入した時には、 色々と実験するために、シリーズ「S2」も数個、あった。 ところが、こちらはファームウェアのバージョンが違っていた。 ネットで情報を仕入れて、XBee書き込みツールをネットから探してダウンロードし、インストールしてみた。 その改訂した書き込みツールから書き込もうとすると、なんとチャンネルや「MYアドレス」が書き込めない(^_^;)。

ここで色々とXBee関連情報を調べて判明した結論は、以下である。 XBeeシリーズ「S1」では、完全に従来のRS232Cなどシリアル通信を置換する「トランスペアレントモード」が機能して、 ピアツーピア、つまり自分の相手を指定して通信する。 これに対して、機能向上版の筈のXBeeシリーズ「S2」では、 主眼がATモードやAPIモードやZigBeeネットワークにあるとしても、 「トランスペアレントモード」が「ビアツーピアにならない」のであった(^_^;)。 つまり、シリーズ「S2」では、XBeeは自分が受信した情報に対して、 その送り手を指定できない(同時に複数から来た情報が混ざってしまう)というのである。

・・・これでは、ちょっと、使えない(^_^;)。 手元に数個あった、シリーズ「S2」のXBeeは、将来の「多対多」通信まで、お蔵入りである。 仕方ないので、まずシリーズ「S1」のXBeeを、業者に発注した。 いずれ届いたら、余った1個のペアから、XBeeの設定書き込みを再開することにしよう。 そして、38400bpsに書き込んで動作確認したXBeeペアを以下のようにSUAC boardとXBeeレシーバにセットした。 Maxの走るホストのMacには、MIDI I/FのUM-2と、Propellerと、XBee受信と、計3ポートのUSBが同時に接続されている。

XBeeとの接続に関しては、Propellerではジャンパの設定は関係ないことを確認して、 さらにPropellerのポートを「P26 - XBee入力」と「P27 - XBee出力」を確認した。 XBeeシリアル通信ライブラリについては、 2012年10月18日 にあった「XBee_In3.spin」「XBee_Out2.spin」をコピーして「XBee_In4.spin」「XBee_Out3.spin」にリネームして、 ボーレートを「19_200」→「38_400」とした以外は、 そのままのプロトコルを継承する方針とした。

・・・しかしここから約2時間、いろいろと苦闘があった(^_^;)。 既に出来上がっているシステム上でのプログラム開発というのは、 特に前段のタタキ台(テンプレートやサンプルやソフトウェア部品)があれば、それらを組み合わせて試行錯誤できる。 ところがこの作業のように、動作の前提となるハードウェアのデバッグというのは、 実験のためのソフトウェアが正しく動くことが何も保証されていない。 ここが(ハードウェア)デバッグの醍醐味であるが、まずは「XBeeが通信できない」という現象にいきなり遭遇した。 何か1バイトでも、それも送信か受信かどちらか一方でも、何らかの兆しがあれば、そこが突破口になるが、 ウンともスンとも言わないのである。

経験的に、これはもしかして・・・とあれこれ試していって、遂にバグを発見した。やってもーた(^_^;)。 ときどきやるミスであるが、手配線であれば「付け替え」で済むところ、基板だと次回の修正が必要となる。 ここ にあった、 この写真 で判明したのは、XBeeの「Din」と「Dout」というのが反対だ、という事実であった(^_^;)。 Propellerにすればシリアル入力、そしてこの基板システムから見てもXBee受信、という「入力」である。 しかし、搭載された無線モジュール部品のXBeeの立場では、無線で受信した情報をPropellerに渡す信号というのは、 XBeeからの「データ出力」なのである。 ついつい、Propellerの立場で「入力」のところに、インターフェースの「受信」というのを繋いでしまう、 過去に何度もやった失敗なのだった。

これがPropellerだけのシステムであれば、基板のハードウェアはそのままにして、 Propellerの方の「送信」「受信」に割り当てたポートの定義を逆にするだけで対応できてしまう。 しかし、この基板にはArduinoとAKI-H8も載るので駄目なのである。 ArduinoやAKI-H8など、一般のマイコンではシリアル通信はUART(汎用非同期送受信)モジュールという専用ハードウェアで行うので、 通信ピンは当然ながら固定である。 ソフトだけでシリアル通信してしまうPropeller(ソフトで送受信のピンを自在に指定できる)の方が、他に例のない凄いマイコンなのだ。 仕方ないので、以下のように基板の切り張り、といういつもの手で、XBeeの信号を反対にして実験すると、 とりあえずワイヤレスの送信から動作を確認できた。

・・・そしてさらに約2時間、またまた苦闘が続いた。 XBee送信が出来たとすれば、信号の取り違えはないので、XBee受信が出来るだろう、 と思えるが、そう簡単でもないのである。 基本的に、「送信」というのは「暇がある時に行う」ので簡単であるが、「受信」というのは、 いつ来るか分らない状態で常に待機/監視していなければならず、 さらにその瞬間に忙しいからといって待ってくれない、厳しい処理なのである。 これは「非同期通信」の本質である。

ここから試行錯誤とともにいろいろなトラブルを整理して、 詳細は省略するが、遂に以下のプログラムで、「MIDI送受信とXBee送受信とビデオ描画」を同時に走らせることが出来た。 やっている事は、12/29最後に走らせたものに、一見すると似ているが、まったく違う。

以前のプログラムと似たプロトコルでMax側からライブの10バンドのグライコデータをMIDIで送るが、 PropellerはいったんこれをMIDI受信して、そのまま、XBeeのワイヤレスでMaxに送り返す。 そしてMaxは、XBeeからシリアルで受けたデータを、さらに再び、そのままXBeeからPropellerにワイヤレスで送る。 そしてPropellerは、このXBeeで受けたデータを元にビデオ信号でグラフィックを生成して描画しつつ、 さらにそのデータをMIDIでMaxに送り返す。 なんと、敢えて無駄に、相当のトラフィックで続く情報伝送を、2往復もやっているのである。(^_^;)

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

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  colors[64]
  word  screen1[x_tiles * y_tiles]

OBJ
  midiIn        : "MidiIn03"
  midiOut       : "MidiOut01"
  serialOut     : "XBee_Out3"
  serialIn      : "XBee_In4"
  tv[1]         : "E_TV02"
  gr[1]         : "E_Graphics04"

PUB start | i, dx, dy, dummy
  midiOut.start(25)
  longmove(@tv_status1, @tvparams, 14)
  tv_screen1 := @screen1
  tv_colors1 := @colors
  tv[0].start(@tv_status1)
  gr[0].setup(x_tiles, y_tiles, x_origin, y_origin, bitmap_base1)
  repeat i from 0 to 63
    colors[i] := $00001010 * ( (i+4) & $F ) + $2B060C02
  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)
  gr[0].clear
  serialIn.start(26)
  serialOut.start(27)
  dummy := midiIn.start(24)
  midiOut.fifoset($C00000 + dummy & $00007F)  ' display total number of Cogs

  repeat
    dummy := midiIn.event
    if dummy <> -1
      serialOut.fifoset(dummy)

    dummy := serialIn.event
    if dummy <> -1
      midiOut.fifoset(dummy)
      if (dummy & $FFFF00) == $B00000
        display(0, dummy & $00007F)
      elseif (dummy & $FFFF00) == $B00100
        display(1, dummy & $00007F)
      elseif (dummy & $FFFF00) == $B00200
        display(2, dummy & $00007F)
      elseif (dummy & $FFFF00) == $B00300
        display(3, dummy & $00007F)
      elseif (dummy & $FFFF00) == $B00400
        display(4, dummy & $00007F)
      elseif (dummy & $FFFF00) == $B00500
        display(5, dummy & $00007F)
      elseif (dummy & $FFFF00) == $B00600
        display(6, dummy & $00007F)
      elseif (dummy & $FFFF00) == $B00700
        display(7, dummy & $00007F)
      elseif (dummy & $FFFF00) == $B00800
        display(8, dummy & $00007F)
      elseif (dummy & $FFFF00) == $B00900
        display(9, dummy & $00007F)

PUB display(num, data)
  gr[0].colorwidth(num//3+1,0)
  gr[0].box(num*25+5, 0, 21, data*192/128)
  gr[0].colorwidth(0,0)
  gr[0].box(num*25+5, data*192/128+1, 21, data*191)

DAT
tvparams      long    0               'status
              long    1               'enable
              long    %000_0000       'pins --- 0...2=[000_0000] , 4...6=[000_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

YouTube
そして、さすがにPropellerのMIDI処理もXBee処理もFIFOバッファが64longsと浅いためか、 上のビデオのように、時間が経つ(データが溜まる)と、遂にはバッファオーバーフローでデータのやりとりが停止した。 ただしPropellerのEEPROMにプログラムを書いたので、リセットスイッチで復旧する、という事である。 ここのトラフィックはあまりに過酷なものであり、一般に人間や自然現象と対峙するシステムであれば、 もっともっと情報のトラフィックは少ない、という「いじわるテスト」である。 あらためて、システムの動作確認とともに、Propellerで相当なパフォーマンスが出る、と確認できた。
■SUAC board ver.0.5からの改善点リスト■

●バグなので次バージョンで必ず改訂する項目
・XBeeのDinとDoutが逆(^_^;) ← とりあえずは基板側で修正する

●必須ではないが改訂することになれば盛り込みたい項目
・電源コネクタ
・電源給電表示LED
・半固定抵抗の穴を2mmφにする

●その他メモ

この時点で、手元にメモっている「次回の基板のための改訂点」は上のようになった。 仕事始めの初日から12時間も仕事するのもどうかと思うが(^_^;)、「やった」という充実感である。

2013年1月5日(土)

昨日は相当に進んだが、あまり飛ばさずに、この週末の研究室はスローペースである。 MIDIとXBeeの外部シリアル通信の部分まで確認できたので(一部バグも発見したが(^_^;))、 いよいよこの基板の拡張機能の本命、パラレルポートの拡張部分の確認である。 まずは、パラレル出力(8ビット×8ポート=64ビット)について、以下のように今後のチェック治具にできるように、 きちんとコネクタからケーブルを引き出すことにして、外部基板に64個のLEDを並べた。 同じ色でも面白くないので、ポートごとに色を変えたり、部品棚に余っていたLEDを適当に組み合わせたりしてみたが、特に意味はない。

そして、ここから長い単調な作業である。 64ビットという事は、、以下のように64個のLEDの2端子で128カ所、それぞれに付く電流制限抵抗(220Ω)の2端子で128カ所、 のハンダ付けがまず必要である。実際にはGNDラインもある。

そしてさらに、以下のように基板のコネクタ部分のハンダめっきが64カ所、64本のリボン線の両端のハンダめっき、そして接続、という作業である。 まさに半日、これで費やされた。

そして夕方になり、ようやくハンダ付けが完了した。 そこで、以下の情報を再び掘り出して、とりあえずのPropellerプログラムを走らせたところ、以下のようになった。 「全て消す」「全て点灯させる」というつもりが、なんか変である。(^_^;)

  • Propeller
    • P8-P15 - 汎用入出力拡張バスライン
    • P16-P18 - 汎用入出力アドレス(A0-A2)
    • P19 - 汎用入出力・出力574ラッチパルス(CK)
    • P20 - 汎用入出力・入力245イネーブル(G)
    • P21 - 汎用入出力・AD7829イネーブル[1](CS/RD)
    • P22 - 汎用入出力・AD7829イネーブル[2](CS/RD)
    • P23 - 汎用入出力・AD7829変換開始(CONVST)
    • P24-P25 - MIDI入出力
    • P26-P27 - XBee入出力

まぁ、シンプルなハードウェア拡張といっても、どこかに何かあるわけで、ここからが楽しい時間である。 回路設計に問題があるのか、フラットパッケージICのハンダ付けが問題だったのか、 今日の配線作業に問題があったのか、可能性は全てあり、だからこそ面白い。 テスターのチェックで済むか、オシロスコープが必要になるか(^_^;)。 これは明日の楽しみとして、今日はここまでである。

2013年1月6日(日)

冬休みもほぼ終わりの週末である。 講義が再開するのは1/9(水)からだが、明日1/7(月)の夕方には、 院生の修了制作検収期限がやってくる。伊熊さんも最後の追い込みである。 そして祝日の巡り合わせの関係で本年度は1/9(水)は「月曜講義日」で、来週はまだ僕は講義が無いので、 もう少し、Propellerと遊べそうである。(^_^)

夜中にフト目覚めたり、早朝の目覚める瞬間に、それまで頭にあった事が鮮明に解決する、 というのは、中間子理論の着想に至った湯川秀樹先生の逸話に限らず、凡人の我々でもよく体験する。 要するに、直面している問題・課題については、ずっと頭の中に(無意識にでも)置いておけば、 人間は眠っても脳は眠らないので、いずれ解決への道筋に導かれるのである。

今朝はまたコレがあり、昨日、うまく動かなかった原因が一気に閃いた。 これに関連しては、基板の一部修正(部品追加)の検討が必要、というのも瞬時に思いついた。 さらに、一昨日の最後の実験で、MIDIとXBeeとで2往復させてグラフィック描画していると、 やがて動作が停止する、という現象の真の理由も思いついた。 今日はこれら3点を忘れないようにメモして、期待しつつ研究室に出てきたのである。

メモの1点目の動作不良の原因は、昨日のプログラムでは

  • Propeller
    • P8-P15 - 汎用入出力拡張バスライン
    • P16-P18 - 汎用入出力アドレス(A0-A2)
    • P19 - 汎用入出力・出力574ラッチパルス(CK)
という、パラレル出力に関するところしか見ていなかったからだ、と思いついた。 設定は少なくともP22までは必要なのであった。 P8-P15のバスラインを出力に設定して、138に与えるアドレスで8ポートから1つを選択して、 138のG入力の立ち上がりエッジで、選択された574だけ、クロックの立ち上がりエッジによってバスラインの情報がラッチされる、 という事である。 ところがこのバスラインは、今回はパラレル入力や2個のA/Dコンバータにも使われるのだった。 そこで、パラレル入力の3ステートバッファ245のイネーブルを配分する138のG入力が不定だと、 せっかくのバスラインがバスファイトする可能性があったのだ。 これは、2個のA/DコンバータAD7829の出力イネーブル(CS/RD)についても同じである。

そしてこれに関連して、メモの2点目の「基板の一部修正(部品追加)の検討」が必要である。 PropellerとAKI-H8については問題ないが、Gainerでは多くの信号が、そしてArduinoでもAD7829に対して、 disableする端子が無い(^_^;)ので、基板に搭載された2個の138のG入力と、 2個のAD7829の出力イネーブル(CS/RD)、計4本のラインについて、pull-up抵抗が必要になるのである。 さらに、このpull-up先の電圧として、ホストマイコンに対応して、+5Vとするか+3.3Vとするか、のジャンパが必要である。

・・・というあたりまでを布団の中で目覚める瞬間に、一気に思いついたのであった。 そしていざ、基板のPropellerに、改訂した以下のようなプログラムを送ってみた。 一定時間ごと(Propellerのメインルーチンが10000回ループするごと ! )に、 8ビットに「55」「AA」という、1ビットごとに交互に点灯するパターンを、8ポート全部に送る、というプログラム「outport_check.spin」である。 プログラムサイズは、たったの25ワード(longs)である。(^_^;)

CON
  _clkmode = xtal1 + pll16x
  _xinfreq = 5_000_000

PUB start | k
  port_initial(0)
  k := 0
  repeat
    k++
    if k == 10000
      port_initial($55)
    elseif k == 20000
      k := 0
      port_initial($AA)

PUB port_initial(data) | i
  dira[23..8]~~                 ' output
  outa[23..8] := $FF00
  outa[15..8] := data
  repeat i from 0 to 7
    outa[18..16] := i
    outa[19] := 0

これで一気に解決するかと思いきや、あまり状況は変わらなかった(^_^;)。 そして、しばし回路図を追いかけて発見したのは、 138のG入力や245のG入力は負論理であるが、 なんとAD7829の出力イネーブル(CS/RD)は正論理である、という事実だった。 普通のICでは、イネープルは負論理、つまりHiで停止、Lowで稼働、ということなのだが、 こちらは論理が反転していたのだった。 正解は以下のようになった。

CON
  _clkmode = xtal1 + pll16x
  _xinfreq = 5_000_000

PUB start | k
  port_initial(0)
  k := 0
  repeat
    k++
    if k == 10000
      port_initial($55)
    elseif k == 20000
      k := 0
      port_initial($AA)

PUB port_initial(data) | i
  dira[23..8]~~                 ' output
  outa[23..19] := %10011
  outa[15..8] := data
  repeat i from 0 to 7
    outa[18..16] := i
    outa[19] := 0
    outa[19] := 1
これで、追加が必要になったpull-upとジャンパについても、以下のように変更されることになった。 まず、2個の138のG入力の2本にpull-upが必要である。 このpull-up先の電圧を+5Vとするか+3.3Vとするか、のジャンパも必要である。 そして、2個のAD7829の出力イネーブル(CS/RD)の2本はpull-downが必要であるが、 この先はGNDなのでジャンパは不要である。

上のプログラムで、一部の列はLEDが期待通りに点灯するようになった。 ただし、まだウンともスンともいわない列の方が多い。 しかしここからがデバッグの真骨頂である。 過去の多くの経験では、基板上のICに指先をあてて温度上昇からトラブルや故障を発見し、 わずかな匂いから部品の劣化や故障を発見してきた。 そしてここで基板にハンドパワーを加えることで、遂に「真のトラブル原因」が判明した。(^_^)

ハンドパワー、つまり、基板上のフラットパッケージを指でグイと押してみると、治具基板上のLEDの点灯状況が変化したのである。 これはつまり、ほぼ初めてトライした、フラットパッケージICのハンダ付け不良である。 574の特定のビットの足が浮いていればそのビットのLEDだけ点灯しないが、 574のCK入力端子、あるいはそれを送っている138のあたりにハンダ不良があれば、 8ビット全部が点灯しなくなる。 点灯している列も点灯していない列も、特定ビットのLEDがまったく点灯しないのは、 バスバッファの245の該当ビットのハンダ不良が疑われる。

そこで、このチェックプログラムをPropStickのEEPROMに書き込み、 作業台に移動して、電源を入れながら(Propellerを走らせて)、全てのフラットパッケージICの端子に対して、 フラックスを塗ってハンダごてを再度あてる、という作業を始めた。 すると、どんどん消えていたLEDが点滅を始めて、64個の中で1個を除いて、 全てのLEDが正常に点灯した。 こうなれば、残った1個はLED不良というよりも、「さかさま」が疑われる。 電源を切ってチップを見ると、案の定、 このLEDだけ「さかさま」だったので、配線で逆方向に修正して、 遂に、以下のように、無事に「outport_check.spin」が正しく走った。 今後、基板を追加で制作したら、まずはこの治具をコネクタに差し込んで、「outport_check.spin」でチェックする事になる。

YouTube

昨日、半日かけてハンダ付けした64個のLEDが、こうも整然と点灯してくれていると、 もっと色々なパターンで点灯させたくなる。 そこで、いつものMIDIでなく、せっかく開通したXBeeを経由して、ホストのMaxからパターン番号を送ると、 基板側のPropellerが対応したパターンでLEDを点灯させる、 というプログラムを作ってみる事にした。 そして、その最初のステップで、またつまづいた(^_^;)。

なんと、「全部のLEDを消す」というPropellerからのコマンドに対して、4列目と5列目だけ、 うっすらとLEDが全部、点灯しているままなのである。 データをあれこれ変えて送って試してみると、「何か1ビットでもLEDが点灯していれば正常」、という不思議な現象であった。 8ビットに「55」「AA」という、1ビットごとに交互に点灯するパターンであれば問題は発覚しないが、 その列の全部のLEDが消えている、という時にだけこの異常が起きたのである。 すでに夜になっていたので、ここで問題を残して、帰宅した。こういう日もある。(^_^;)

2013年1月7日(月)

消化不良のトラブルを残したまま、翌日になった。 この日は伊熊さんの修了制作の検収期限でもあるが、とりあえず、また起床時に思いついた対処法をメモして出勤した。 2列だけ、8ビット全てのLEDがOFFというデータの時にだけ、「うっすらと」点灯する、という現象であった。 その列が、例えば「3と7」であれば、「011と111」で共通点があり、そこを手がかりに追いかけられる。 ところが、問題の起きたのは「4と5」であり、バイナリで「100と101」というのは、あまり論理的に繋がらない。

「うっすら」というのも不思議だが、いずれかのビットが点灯していれば他のビットはちゃんと消える、というのが最大のヒントである。 この574の出力からのLED点灯チェック治具については、負論理でなくて正論理で構成した。 つまり、74HC574の電流供給能力に頼って、ピンから220Ωを経てLEDのプラス側(アノード)に行き、 LEDのマイナス側(カソード)からGNDに繋がっている。 つまり、「点灯」しているLEDのビットだけ+5Vに上昇して電流が流れ、「消灯」しているLEDのビットでは「Low」状態のまま、 という事であり、全ビット「消灯」という問題のケースの時だけ、まったくその574が電流を消費していない。 その時だけ「うっすら」点灯するというのは、つまり、GNDの側が浮いているのでは・・・というのが対策アイデアであった。

そこで再び、問題となっている「4と5」列の574にハンドパワーを加えてみると、 つまりグッと押してみると、一瞬、ちゃんと点灯した(^_^)。 これは予想通り、この2個の574のハンダに、一部、まだ不良が残っていたのである。 そして改めてフラックスとハンダごてを駆使して、遂に、無事に想定通りの動作として、この治具が完成した。 せっかくなので、「outport_check.spin」を以下のように改訂して、全ビットON/全ビットOFFもチェックするようにした。

CON
  _clkmode = xtal1 + pll16x
  _xinfreq = 5_000_000

PUB start | k
  port_initial(0)
  k := 0
  repeat
    k++
    if k == 20000
      port_initial($FF)
    elseif k == 40000
      port_initial($00)
    elseif k == 60000
      port_initial($55)
    elseif k == 80000
      port_initial($AA)
    elseif k == 100000
      k := 0
      port_initial($00)

PUB port_out(address, data)
  outa[15..8] := data
  outa[18..16] := address
  outa[19] := 0
  outa[19] := 1

PUB port_initial(data) | i
  dira[23..8]~~                 ' output
  outa[23..19] := %10011
  repeat i from 0 to 7
    port_out(i, data)
    outa[19] := 1

YouTube

ここで、M2の伊熊さんから「検収の準備が出来ました」とメイルがあり、 このように 動作確認、検収を完了して、お昼になった。 あとは口頭試問と最終報告会、そして卒展の展示である。 暗いところでないと動作しないので、記録動画の撮影と編集にはちょっとテクニックが必要になりそうである。

そして午後になり、あれこれ事務仕事が舞い込んだりしながら、昨日の続きに着手した。 XBeeを経由して、ホストのMaxからパターン番号を送ると、 基板側のPropellerが対応したパターンでLEDを点灯させる、というものである。 一昨日の実験で完成していた「board_006.spin」から、MIDIとグラフィックを外して、 XBeeだけは通信動作確認のために双方向にした「board_007.spin」として、 あれこれと楽しみながら作ったのが、以下である。 プログラム開発の所要時間は、最初の7つ(case 0からcase 6)までで計30分、そして最後の1つ(case 7)が20分である。 ハードウェアが確実に動く場合には、ソフトウェアの開発はこれほど安心で楽しい頭の体操なのだ、とまた再確認した。

CON
  _clkmode = xtal1 + pll16x
  _xinfreq = 5_000_000

OBJ
  serialOut     : "XBee_Out3"
  serialIn      : "XBee_In4"

PUB start | i, k, dummy, mode
  port_initial(0)
  serialIn.start(26)
  serialOut.start(27)
  mode := 0
  k := 0
  serialOut.fifoset($C0007F)

  repeat
    dummy := serialIn.event
    if dummy <> -1
      if (dummy & $FFFF00) == $C00000
        mode := dummy & $00007F
        serialOut.fifoset($C00000 + mode)
        port_initial(0)
        k := 0
    case mode
      0 :
        port_initial($00)
        mode := 100
      1 :
        port_initial($FF)
        mode := 100
      2 :
        k++
        if k == 5000
          port_initial($55)
        elseif k == 10000
          k := 0
          port_initial($AA)
      3 :
        k++
        if k == 8000
          k := 0
        if k//1000 == 0
          repeat i from 0 to 7
            port_out(i, 1<<(k/1000))
      4 :
        k++
        if k == 8000
          k := 0
        if k//1000 == 0
          repeat i from 0 to 7
            port_out(i, ((%10001000100010001<<(k/1000+i)) & $FF00)>>8)
      5 :
        k++
        if k//100 == 0
          repeat i from 0 to 7
            port_out(i, k/(2<<(7-i)+11))
      6 :
        k++
        if k == 8000
          k := 0
        if k//1000 == 0
          repeat i from 0 to 7
            port_out(i, 1<<((k/1000+i)&3)*16 + %1000>>((k/1000+i)&3))
      7 :
        k++
        if k//100 == 0
          repeat i from 0 to 7
            port_out(i, ( %000000011111111>>(7-((k/(70-i*9))//256)>>5) ) & $FF)

PUB port_out(address, data)
  outa[15..8] := data
  outa[18..16] := address
  outa[19] := 0
  outa[19] := 1

PUB port_initial(data) | i
  dira[23..8]~~                 ' output
  outa[23..19] := %10011
  repeat i from 0 to 7
    port_out(i, data)

YouTube

さて、ようやく調子が出て来たところで、まだ宿題があったのを忘れてはいなかった。 1/6(月)の冒頭に、「さらに、一昨日の最後の実験で、MIDIとXBeeとで2往復させてグラフィック描画していると、 やがて動作が停止する、という現象の真の理由も思いついた。 今日はこれら3点を忘れないようにメモして、期待しつつ研究室に出てきた」と書いていた。 この3点目について、チェックを片付けた上で先に進みたいのである。

以前にこのページで、Propellerのグラフィック表示について、 「グラフィック(ビデオ出力)で2個もCogも使うのは、1個のCogは刻々とビデオ信号のタイミングに合わせて、 画面内の画素ごとに外部の簡易D/Aでビデオ信号にするためである。 もう1個のCogは、テキストのフォントテーブルを参照したり、 ドット・ライン・三角形・矩形(二つの三角形として)・円弧・楕円などのグラフィック要素を計算して、 これを画素データに展開するための仕事を担当しているのである」と書いていた。 問題はこの2個のCogの動作のうち、後者の部分なのである。

「電子十二影坊」 での経験で、Propellerのグラフィックプログラムを開発した任田さんと小畑さんとともに、 直面した「Propellerの限界」は、メモリの容量制限とともに、このグラフィック処理の重さだった。 つまり、ライブラリとしてはCogを分割しているように見えるが、メインから描画コマンドとともに呼ばれると、 グラフィックライブラリ中のCogがその描画処理を展開して戻ってくるまで、 呼び出し側のメインのCogは、ただ待ちぼうけしているのである。 これが、多数の描画処理をずらりと並べるほど、全体のメインループの回るスピードが遅くなる理由である。

そこで、1月4日の最後にやった実験の「SUACboard_test006.maxpat」をそのまま使い、 Propellerの側の「board_006.spin」から、グラフィック処理をコメントアウトした「board_008.spin」で実験してみた。 ビデオ出力は無くなるが、

  • Maxのjitterでビデオを再生
  • このサウンドを10バンドのBPFで帯域レベルを50msecごとに検出
  • そのレベルデータをMIDIで送信、データをスライダー★で表示
  • PropellerはこのMIDIを受信して、そのまま同じ形式でXBeeから送信
  • MaxはXBeeで受信したデータを、そのまま同じ形式でXBeeから送信
  • PropellerはこのXBee受信データを、そのまま同じ形式でMIDIから送信 ※グラフィック描画せず
  • MaxはこのMIDI受信データを、★の下に同じように並べて表示
という流れである。 想定としては、これだと64longsのFIFOバッファは溢れずに、ずっとスライダーは同じように動くのでは、という見立てである。 そして予想通りに、「board_006.spin」からグラフィック処理をコメントアウトしただけのバージョンの「board_008.spin」で、 以下のように、いくら走らせても止まることが無い、と確認できた。(^_^)

YouTube

こうなると、せっかくなので、ポートチェック用の治具の64個のLEDでバーグラフ表示をさせてみたくなる。 そこで、以下のように「board_008.spin」を改訂して、見事に、こちらもへこたれずにずっと走る、 「過酷な2往復通信+グラフィック」を実現した。 10バンドのイコライザのうち、両端の2バンドを除いた8パンドの値を使っている。 システムの動作は以下である。

  • Maxのjitterでビデオを再生
  • このサウンドを10バンドのBPFで帯域レベルを50msecごとに検出
  • そのレベルデータをMIDIで送信、データをスライダー★で表示
  • PropellerはこのMIDIを受信して、そのまま同じ形式でXBeeから送信
  • MaxはXBeeで受信したデータを、そのまま同じ形式でXBeeから送信
  • PropellerはこのXBee受信データを、そのまま同じ形式でMIDIから送信しつつ、8バンドの値を8列のLEDでバーグラフ表示
  • MaxはこのMIDI受信データを、★の下に同じように並べて表示
CON
  _clkmode = xtal1 + pll16x
  _xinfreq = 5_000_000

OBJ
  midiIn        : "MidiIn03"
  midiOut       : "MidiOut01"
  serialOut     : "XBee_Out3"
  serialIn      : "XBee_In4"

PUB start | i, dx, dy, dummy
  port_initial(0)
  midiOut.start(25)
  serialIn.start(26)
  serialOut.start(27)
  dummy := midiIn.start(24)
  midiOut.fifoset($C00000 + dummy & $00007F)  ' display total number of Cogs

  repeat
    dummy := midiIn.event
    if dummy <> -1
      serialOut.fifoset(dummy)

    dummy := serialIn.event
    if dummy <> -1
      midiOut.fifoset(dummy)

      if (dummy & $FFFF00) == $B00000
      elseif (dummy & $FFFF00) == $B00100
        port_out(0, ( %000000011111111>>(7-((dummy & $00007F)>>4)) ) & $FF)
      elseif (dummy & $FFFF00) == $B00200
        port_out(1, ( %000000011111111>>(7-((dummy & $00007F)>>4)) ) & $FF)
      elseif (dummy & $FFFF00) == $B00300
        port_out(2, ( %000000011111111>>(7-((dummy & $00007F)>>4)) ) & $FF)
      elseif (dummy & $FFFF00) == $B00400
        port_out(3, ( %000000011111111>>(7-((dummy & $00007F)>>4)) ) & $FF)
      elseif (dummy & $FFFF00) == $B00500
        port_out(4, ( %000000011111111>>(7-((dummy & $00007F)>>4)) ) & $FF)
      elseif (dummy & $FFFF00) == $B00600
        port_out(5, ( %000000011111111>>(7-((dummy & $00007F)>>4)) ) & $FF)
      elseif (dummy & $FFFF00) == $B00700
        port_out(6, ( %000000011111111>>(7-((dummy & $00007F)>>4)) ) & $FF)
      elseif (dummy & $FFFF00) == $B00800
        port_out(7, ( %000000011111111>>(7-((dummy & $00007F)>>4)) ) & $FF)
      elseif (dummy & $FFFF00) == $B00900

PUB port_initial(data) | i
  dira[23..8]~~                 ' output
  outa[23..19] := %10011
  repeat i from 0 to 7
    port_out(i, data)
    outa[19] := 1

PUB port_out(address, data)
  outa[15..8] := data
  outa[18..16] := address
  outa[19] := 0
  outa[19] := 1

YouTube

これで、懸案だったメモのポイントは、全て解決したことになる。 伊熊さんの修了制作の検収も、作品要旨の提出まで済ませて、こちらも完了である。 実は、年末年始にメモしていた事項があり、パラレルポート出力は、まだ本来の実力の一端だけであり、 ここから、いよいよPropellerのプログラミングの本番が待っている。 64ビットのパラレル出力をONかOFFか、というディジタルで出すのは、いわば当たり前である。 この64ビットのそれぞれを、別個にPWM制御することで、かつて 「靄夜」(もや) の時に、それまでのAKI-H8プログラミング・テクニックの集大成として、 最大限にチューニングした割り込みプログラムで実現した機能を、 この基板でも搭載したいのである。 Propellerでこれを実現するには、ここまで簡単にやってきたspin言語でなく、 間違いなくアセンブラでの高速処理ライブラリをゼロから開発する必要がある。 ここが、この基板の一番のポイントである、と最初から決めていたが、その入口にようやく到達したのだ。

いろいろ遅々として進みながら、次第に基板が逞しく成長してきた。 今日はここまでとして、ぼちぼち日記も(2)に進んで、さらに基板のチェックと、本命のPWMライブラリに挑戦していこう。

続々・Propeller日記(2) へ