組み込みでのC++の勧め

IMG_2863

PICならxc32++,armならarm-g++,など、さまざまなマイコンc++を利用可能です。例えば32bitCPUならアドレスがリニアに取れることが多いため、オーバーヘッドが少なくてすみます。

そこでc++をつかったプログラミングのススメを書きます。ではなぜC++なのでしょうか?

  • C言語と相性がいい
  • クラスなどが利用できる
  • ライブラリを作る時に便利
  • デバックしやすい

最近ではPCのプログラミングもオブジェクト指向が多いです。Javaとかc#とかもそうです。

しかし、組み込みで使う時には結構詰まる点もあるのでここで少しポイントを押さえておきましょう。

1、文字列関係 まず組み込みでは当たり前ですがstreamが存在しません。自作するなどする必要があります。Cでも同じですが。Stringなども実装されていなかったりとか、以外と実装されていないことが多くてやってみると以外とつまることも多いです。

2、コンストラクタの初期化 コンストラクタの初期化はスタートアップルーチンの最後で行いますが読み出し順序は定義されません。そのため組み込み特有のレジスタアクセスが競合する可能性のある場合は手動で初期化する必要があります。 たとえばオシレータのクロックがあります。この設定値をレジスタアクセスしてクロックを計算しても、その後にオシレータの設定をするとその設定値が狂ってしまいます。UARTなどを使う場合は注意が必要です。

また、C++のオーバーヘッドも場合によっては注意が必要です。関数(メンバー)へのアクセスの方法がCとは異なります。そのため呼び出し時に時間がかかります。たとえば低レベルのもの(ベクトル型とか)はinline修飾子をつけておきましょう。もしかしたら最適化でつくかもしれませんが。

staticにしたりしてヘッダに入れなければなりません。

machiKaniaでマインスイーパー

IMG_2777 IMG_2778

再帰の展開をしてマインスイーパーを作りました。後の方に載せます。ソースコードGithubにあげています。うまくカラー表示できてないけど。

以前C言語で作ったものの移植です。マインスイーパー自体は非常に簡潔なコードでかけますが、掘る作業で再帰を用いるのでこれではスタックが少ないマイコンだとオーバーフローするのでまた別にスタックを用意して呼び出します。

このため少々コードが煩雑になります。掘る作業について補足しましょう。

掘る座標(x、y)に対して

1、自身の座標を開きます。

2、再帰で自身の関数を呼び出して周辺8方向を開きます。

と実装するのですが、300以上再帰するのでダメです。過去に掘った情報は塗りつぶしアルゴリズムにおいて必須なのでこれをスタックに保管して処理をしましょう。なのでこうします。

1、開く最初の座標をプッシュします。

2、その周りの開けるところの座標をプッシュします

3、ポップして座標を開きます。

[c] LABEL DIG var x,y,i,a,b,z

x=ARGS(1) y=ARGS(2) i=0

t(i,0)=x t(i,1)=y

do x = t(i,0) y = t(i,1) if f(x,y) f(x,y)=f(x,y)+10 else i=i-1 if i endif

a = t(i,0) b = t(i,1)

if f(a,b)-10=(gosub(cflags,a,b)) then for x=a-1 to a+1 for y=b-1 to b+1 if gosub(isinfi,x,y) then if f(x,y) i = i+1 t(i,0) = x t(i,1) = y endif endif next next endif loop while i return [/c]

では。

MachiKaniatypeZのビデオ再生(完結

あけましておめでとう。(遅い

MachiKaniatypeZでカラー動画再生をやったので技術的メモ

カラー動画再生をするのですが、出せる色数は16色です。カラーパレットを高速に切り替えないといけません。しかもFPS30だとすると、表示タイミングは1/2となりますが、ここでSDの読み出し速度を考えると1F以内に処理は完了しないので2Fかかると試算します。

なので読み出し時にはバッファを用意して切り替えながら表示する必要があります。ダブルバッファリンクと呼びます。メモリ資源が豊富でないと使えません。

img_2759

パレットも切り替えますが、これもGRAMを切り替えるのと同時に切り替えます。そうしないとパレットが不整合を起こしてうまく表示できません。

実はこれ音声とほぼ同じ仕組みです。音声の方も同様にして再生しています。こちらはリアルタイム性が求められるのでDMAが主な転送を担ってます。

 

MachiKaniaで日本語表示

[caption id="attachment_4051" align="alignnone" width="800"]日本語表示テスト 日本語表示テスト[/caption]

日本語表示テストをしました。上の写真のソースコードはこちらから

https://github.com/elect-gombe/fontx2machikania

FONTX2の説明を書いたことがなかったので載せます。

FONTX2形式は日本語表示などに使われます。最近のコンピュータはフォント表示にアウトラインフォントを持ち入りますが、マイコンで扱うには負荷が高いのでマイコンではよくビットマップフォントが用いられます。このビットマップの種類の一つがFONTX2です。

ShiftJISを文字コードとしています。フォントファイルは全角と半角で分かれています。全角では約8000字入っているので容量が大きくなります。Flashに埋め込む際はこの容量を注意する必要があります。8x8の場合は60kBくらいになります。

FONTX2形式を埋め込むのは結構Flash大食いと思ったんですが、第一水準だけサポートすればサイズが半分になるのでメモメモ。8x8だとコードブロックは50ほどまで下がり、コードサイズは30k台まで下がりました。

ただし例えば「鬱」とか「丼」とか消えます。消えた文字は生き返りません。ではFONTX2形式について説明しましょう。

以後全角の場合について。

FONTX2形式ではヘッダ部とデータブロックテーブル部とフォント本体に分かれる。コードブロックテーブル部にはフォント本体をどのように配置するかを示す。フォントは断続的に配置されているが、そのコードをフォントの実体としてどこコードからどこコードまで、その次がどこコードからどこコードまでというように配置する。そのためコードを取得する際にはこのブロックがないと読み取ることができない。

ヘッダ部にはフォント名などの情報の他にフォントサイズや半角か全角識別子、コードブロックテーブルサイズを含む。

フォント本体にはビットマップフォントが格納されている。これが一番大きいサイズとなる。

全角についてはフォントサイズが非常に大きい。8x8で第一水準だけで3000文字あり、一文字8byteなので24kBになります。ただし漢字以外にもひらがなやカタカナ、記号を含めると30kB以上になります。

逆に半角では一文字8byteで256文字固定なので2kほどで済みます。そのため比較的小さい領域で使用可能です。

フォントサイズについてまとめました。だいたいですので。フォントのサポートによって異なります。

8x8全角 第一水準だけ 30k 第二水準フルで入れると58k 12x12全角 第一水準だけ 90k 第二水準も含めると 180k 16x16全角 第一水準だけ 120k 第二水準も含めると 230k

半角では小さいのであまり気にすることがありませんが、一応紹介します。半角ではフォントの縦横比が違いますので代表値のみ示します。 6x8 2KB 6x12 3kB 8x16 4kB

見ればわかると思いますが、横幅に関して8ドットごとに1バイトで切り上げです。なので全角は8x8と12x12は3倍容量が違います。これはしょうがないですね。

エディタ日本語版

Editorの一部を日本語化しました。日本語というものは非常に文字の種類が多くて困ります。PCG空間が256あってもすでに英文字などでほとんど埋まっています。今回の日本語化も同時表示可能数を超えると文字化けが発生します。(以前表示した文字に置き換わってしまう)。

搭載フォントはMISAKIフォントの第一水準だけサポート版です。30KBほどに収まりました。必要の時に必要なフォントをPCG空間にコピーします。ただし超えたぶんに関しては最初の文字から消去します。

このため表示可能数は100字未満(数えてないけど)になります。古い文字は新しい字に置き換わってしまいます。そのためメッセージ部の一部が化けます。

img_2735

img_2736

MachiKaniaのSDカード読み出しの高速化

WAVの読み出しするときに気がついたんですがSDカードの読み出し遅すぎまあなんというかmicrochip のライブラリを使っているのでしょうがないのかな?とは一瞬思ったのですがオーバーヘッドが大きいのとコードサイズが大きいですね。FatFSだとコードサイズはもちろんのことオプションも豊富なので今後の拡張性が大幅に向上します。最近だと64GBも対応していてさすがだと思いました。

実際にFatFSをつかうとするならば一部書き換えだけで対応できるのですが今回はせっかくなのでセクタリードなどから書いていきます。しかし実際はハードウェアに依存している部分はわずかなので残りの部分は他の方のコードを真似して書くだけです。(あーいけない癖)

SDカードでは内部がブロックによって分割されていて、1ブロックあたり512Bです。たいていの場合このブロックサイズとセクタサイズは一致します。なのでアクセスする際は512バイトごとのセクタアライメントされた状態でアクセスすると高速にアクセスできます。これ以外の場合は必要外のファイルも読み出します。このため二度手間となり速度が低下します。

この問題についてはメモリー構成によって改善することができます。TINYだとバッファリングをせずにそのまま読み出しますので効率が悪いです。ただし読み出し時にセクタアライメントしておけばこのような問題に遭遇することはありません。同様のパフォーマンスを実現できます。

コードサイズについてもELMのリンクに乗ってますがたいていの場合はメーカ製より小さくなり、機能もより増えます。ただし標準入出力ライブラリと互換性はなく、コードに関して相当の箇所を変更する必要があります。

読み出し時の速度についてベンチマークの結果を載せます。以下の結果はおおよそだと考えてください。

1、マイクロチップ社製ライブラリ原型・・・100kB/s

2、マイクロチップ社製ライブラリDMA化・・・200kB/s

3、FatFS、Elm氏のライブラリソフト転送・・・200kB/s

4、FatFS、Elm氏のライブラリDMA転送・・・800kB/s

となりました。マイクロチップ社製ライブラリの性能が悪いのはおそらくファイルシステム部分の性能が悪いためでハードウェア(DMA)で転送してもこの点は改善しませんでした。

逆にFatFSではノーマルではほぼオーバーヘッドは改善され、送信のソフトに処理の時間が移り、その結果DMA化した時に速度が大幅に向上しました。

FatFS+DMAでビデオ出力をしました。

https://github.com/elect-gombe/Video_onMachiKania

パフォーマンスが素晴らしいです。

MachiKaniaでPCMの再生

次期作で乗る予定だったらしいですがもう試しに乗せてみました。まあ、みればわかるとおもいます。解説はほとんど不要だと思います。

2016/12/11追記 YouTubeに変更しました

で、PCMなんですが容量が一気に増えますんでFlashには入りません。(数秒まで) ということはSDカードの使いどころです。大容量なのでもう容量など気にしなくてもいい点がいいですね。アキバ行ったら2GBが最小容量でで4GBが一番安価でって感じなので容量はもう気にする必要などないです。Flashの何万倍か容量がありますし。

読み出し+再生について以下のようにして実験しました 8bit1ch32ksps,unsignedのRaw(ヘッダなし) ビットレートは以下の通りです 8x1x32k=256kbps

例えば5分のものだと10MBくらいです。

バッファサイズについて実験しました 1、2048で再生できました。 2、1024ではぷちぷちしてしまいました。 3、いうまでもないけど512がセクタサイズなので。

負荷についてはバッファサイズが上がると当然瞬間的に上がって下がってを繰り返します。2048では30%ほどでした。ほぼ全てがSDの読み出しなので改善の余地がありそうです。FatFSとDMAにでも移行しようかなあ。

2016/12/13追記

128x96 2ビットグレイの20fpsの連続画像です。一つのファイルにまとめています。なんかせっかく4段階の色表現なのにあまり意味がない気がしますがこれは出力の精度の問題です。ワンチップなんでこんなものだと思って。 また今度に画質改善したいと思います。