(動かして遊べるソースコード付き!)DMAバッファを管理するビデオやオーディオのように絶え間なくやってくるデータの入出力を処理する場合、一般にDMAを使います。3種類に分類する事ができます。DMAは、リクエストを出してからバッファにデータが完全にやってくるまでに時間がかかります。DMAのリクエストを出してから即座にそのバッファに対して処理を開始する事は通常しません。ビデオやオーディオのDMAバッファの管理は、DMAを出してからDMA完了イベントを待ち、到着したデータに対して処理を始める事になります。配列による手法DMAバッファを管理する機構を実現する際によく見かけるのは以下のような配列を用いた手法です。バッファや管理構造体を配列として保持し、何番目が「DMA中」、何番目が「DMA完了」といった具合にインデックスで管理する方法です。非常にシンプルですし、何の問題もないのですが、実装してみると意外とごちゃごちゃした感じになる傾向があります。これは、「システムの全体挙動を見る」という視点を持って見た場合、「配列にアクセスする」という実装詳細が目に入ってきてしまうためなのかもしれません。考え直して、以下のような簡単なモデルを作ってみました。このモデルには登場人物が4人います。queueは、任意の長さを構成可能なFIFOで、「未使用」状態のバッファを格納しておく場所です。delayは、任意の遅延数を構成可能なFIFOで、設定した遅延数でデータが出てくるディレイ・ラインです。viprocは、ビデオやオーディオを入力するモジュールで、データを入力すべきタイミングでのみ実行されるものです。viprocは、自身が呼ばれたらqueueからバッファを取りだし、バッファにデータを入力するためにDMAをリクエストします。加えて、バッファをdelayに押し込んで終了します。voprocは、ビデオやオーディオを出力するモジュールで、データを出力すべきタイミングでのみ実行されるものです。voprocは、自身が呼ばれたらdelayからバッファを取りだし、バッファからデータを出力するためにDMAをリクエストします。加えてqueueにバッファを押しこんで終了します。上記設計の場合、queueの深さは出力DMAが完了するために必要な深さが必要です。その点さえ注意すれば、上記のモデルは以下のようなメリットがあります。実装の抽象度が高く、メインテナンスが容易。データ入力が確定するまでの遅延数をdelay(ディレイ・ライン)の長さで任意に調整可能。バッファ数はqueueの長さで決められ、先読みなどの処理も容易。先の配列による手法では、バッファ管理のためのインデックス変数などが上位に出てきて、ごちゃごちゃした感が否めませんでした。モデルベースによる手法を用いる事で実装の抽象度が上がってシンプルな実装を実現できます。上記に示したメリットは配列による手法でも当然のように実現可能です。実際に実現した実装を比較してみるとモデルベース設計の効果がわかると思います。動かして遊べるソースコード実際に上記のモデルを動かして遊べるソースコードを用意しました。viomodel.tar.gzからダウンロードして下さい。「DMAバッファ管理手法の続編」に続編を書きました。LPCとは、酔漢さんがホストされているTOPPERS/ASPのNXPセミコンダクターズ社向けプロセッサへのポートです。私はほぼ名前だけのメンテナーですが、過去にコミットした私のコードでちょっと良くない点があったので御紹介します。普通はこういう事は書かないのですが、何を考えてそうして、何が良くなかったのかを示してみたい衝動にかられました。問題のコードはTOPPERSの中でも悪名高きUARTに関連する箇所です。オリジナルのtarget_config.cは以下のようになっていました。SIO_PORTIDを参照して必要なコードを生成させるという記述です。ちなみにPINSELは以下のようなマクロです。シリアルポートは「ひとまずシステム唯一」という仮定を用い、ここでよろしくやってくれるわけです。加えて、「使いたいポートと違ったらアプリケーション・プログラマがよろしくやってくれ!」と主張しています。私はここでちょっと「え?」と思いました。「イマドキの人」にそういうのって通じるの?という具合です。ここから私の余計なお世話が始まりました。SIOポートの初期化です。デフォルトでパワーオンされていないペリフェラルに対してパワーオンが必要です。同じTXDやRXDであっても、割り当て可能なピンが幾つか存在します。「一行記述を見れば何が割り当てられているのかわかるのが親切というものではないか!」という主張を基に、以下のような実装に改悪しました。それらのマクロは以下のようにしました。これでアプリケーションプログラマが「おや?私の使いたいピンと違うぞ!」と直ぐに気付く事ができるし、加えて予めマクロが全てのパターンで用意されているので差し替えるだけで準備オッケイ!と相成ります。こりゃ便利だなんて思うわけです。何が改悪なのでしょうか?一見便利になったように見えますが、実は壮大な問題が含まれています。改悪による壮大な問題さて、先ほどのコード、パッと見は良いのですが、オリジナルにない修正を加えています。SIO_PORTIDを参照して初期化するのではなく、SIO_BAUD_RATE_PORTNを見て初期化。target_uart_initの呼び出し。SIO_PORTIDを参照して初期化する場合、該当するある一つのシリアルポートのみが初期化されます。実はとあるプロジェクトで「複数のUARTポートを同等に扱いたいなぁ」と考えていました。これが最初の改悪の動機になりました。「SIO_BAUD_RATE_PORTNが定義されていたらそのシリアルポートを使う!」で良いんじゃない?それって凄く便利かも~!です。良さそうですが、他のポートは依然「SIO_PORTIDを参照して初期化」を期待しています。先の改悪のコードは一切「UARTを初期化しない」というおかしな挙動を生む原因になります。加えてtarget_uart_initの呼び出しです。この関数はpdic/uart/uart.cの関数を呼び出しています。「あれ?pdicって抽象化されたデバイスドライバだよね?」とはたと気づくわけです。要するにここで行なっているのは、下層から上層への呼び出しという、主従関係が逆転する極めて重大な問題というわけです。いうわけで・・・というわけで私の浅はかな判断により改悪したコードによって、メインコミッタである酔漢さんにご迷惑をおかけした次第です。LPC1830を試す(3)でサラッと触れてありますが・・・。恐ろしくて真相は聞けません。LPCM25P16をフルコントロール!M25P16は、SPIバス互換シリアルインターフェースを持つ、16Mビットのフラッシュロムです。8ピンの小さなパッケージから選択可能で、気軽にフラッシュロムを搭載する事ができます。内部ブロックは以下のようになっています。ページサイズ(Xアドレス)は256バイトで、256ページで1セクタです。M25P16で消去可能な最小単位はセクタですので、256ページをまとめて消去(実際にはビットを全て1に)する事になります。ちなみに、M25P16の場合、32セクタあって、総計8192ページ存在します。広大な敷地が広がっています。コマンド群は以下のようになっています。何か別の開発を中心に考えている場合、「一応ちゃんと実装したいなぁ」とか考えて上記の対応を始めると意外に時間がかかります。今日は意外に時間がかかった(わけでもない気がするけど・・・)M25P16の実装を公開します。ダウンロードはこちらから。ソースコードとヘッダから構成されています。ソースコードのSPIマクロに実装詳細を提供すれば、すぐに使えます。SPIのキャラクタについてはデータシートを参照して下さい。以下の検証を実施済みです。セクタ消去を実行する。WRITE」操作用データを生成する。ページライトを実行する。M系列信号発生器を再度同じシード(種)で初期化する。BYTES」操作でデータを読み込んで系列信号と比較。上記を全セクタに対して実行する。M25P16の全バイトをくまなくI/Oできる事を確認して満足満足・・・。「本当にやりたい事」はこの先にあります。KT-i7A4.0」を入手しました。タブレットを、将来的に組み込みシステムのフロントエンドとして使おうと考えています。Androidの開発に慣れておこうという算段です。この機種には残念な事にBluetoothが搭載されていないのですが、気にしません。Nexus7なんて別に欲しくないしっ!(←まったくもって嘘!)http://developer.android.com/index.htmlからSDKをダウンロードしてインストールします。次にドライバ関連の設定。PCに最初に接続した時にはドライバはインストールされないと思います。不明なデバイスとして出ているアイコンからプロパティを辿って下さい。以下は認識後の画面ですが、プロパティに対する値は同じモノが出てきます。ハードウェアIDをandroid-sdk\extras\google\usb_driver\android_winusb.infに追加します。Plug-inの設定を実施。Softwareを選択。https://dl-ssl.google.com/android/eclipse/これで開発環境のセットアップが完了です。フォントをきちんと日本語化デフォルトのフォントがあんまりな感じなので、フォントを変えて気分一新します。android-sdk\platforms\android-16\data\fontsから以下のフォントを使います。DroidSansJapanese.ttfMTLc3m.ttfMTLmr3m.ttf本体にこれらのフォントを転送します。ReadOnlyでマウントされている/systemを書き込める状態でマウントしなおします。adbを使ってシェルインターフェースを出します。shell次にマウント状態を確認します。mount表示されたマウントデバイスから/systemを含むブロックを探し出します。0これから/systemの下を書き換えるのでマウントし直します。/systemexitこれで/systemの下を書き換える事ができます。フォントファイルの転送です。/system/fonts転送した時の様子を以下に示します。0.598s)ちゃんと転送できていますね。次にフォールバック設定を更新します。書き込み可能なローカルディレクトリ名フォールバック設定に上記の3つのフォントを書き加え、本体に書き戻します。/system/etc/これでフォントはばっちり日本語化されます。(Atom)自己紹介shinta基板が大好きな組み込み系エンジニア。電気図面を描いてPCB上に美しく配線できた時に何とも言えない快感を覚える。ソフトウェアとドライバが一式になったパッケージをダウンロードします。インストール後に本体を接続してソフトウェアを起動すると以下のような画面が表示されます。勢いよく「改良しました!」と宣言したh8writeですが、やっぱり書き込みに失敗するという事がわかりました。そもそも真の原因を掴めないまま改良したと言っても、何を改良したのか意味がわかりません。自分でもそんな突っ込みを入れたくなるのですが、その日はグ...システムにおけるレイテンシーとスループットの話題レイテンシーとは、あるシステムに何らかの入力を与え、それに対応する何らかの出力が出てくるまでの時間(遅延量)を指します。ある処理の実行を指令してから実際の結果が得られるまでに250ミリ秒かかったとすると、それは250ミリ秒のレイテンシーを持つシステムという事になります。放置を防ぐアイデアの1つとして「具体的な目標に繋げる」というものを挙げました。アップデートしました。このアップデートにより、以下の動画で示すような長い曲でも難なく再生させる事ができるようになりました。mkIIは便利なのですがオンフィールドで書き換えるには不便ですし、ユーザに書き変えを頼むわけにもいきません。Atmelが公開しているアプリケーションノートAVR109に自己プログラミングがありましたので試してみました。LPC824を使ったサウンドモジュールMicroSoundModuleを開発していました。このサウンドモジュールは、コマンドを受け取って色々な再生を行うもので、当初はこのコマンド処理部分の実装にNT-Shellを用いる計画でした。BlackTankには有機EL液晶が搭載される予定です。接続部分はFPCになっていて、例によってFPC用コネクタなのですが、最初の実装は思いっきり失敗してしまいました。猫も杓子もIoTと皆さんが仰るので、その声が大きくなればなるほど自分は遠ざかる方向で生きていたのですが、そうすると完全に煙に巻かれたお爺さんのようになりまして、今は世の中が進んでおるんじゃのぉと言うだけの人です。moduleにブートローダを載せる(AVR109対応)随分前に対応しようと思い立っていたAVR109にようやく対応させた。以前やった時にうまく書けなかったのはボードのクロック精度が原因。ここ数日モニタを実装していて、思った以上にRC内蔵クロックの精度が悪いことが分かった。エコーバックのテストでやたらと文字が化ける。