こんな寒い日は暑い肉まんでもハフハフしながら(ry
***
マイコンでハフマン符号圧縮が動くようになった。

非可逆圧縮なので当然ながら、目で見てわかるような違いはないのだが。
とりあえず動作確認が目的なので、ADCバッファに48KiB、ハフマンバッファに48KiBを割り当てている。いままではADCに96KiBなので、いつもの半分の高さ。
CGMSとCCAPは不要なので、垂直同期のトリガから一定時間ディレイしてADCを開始したほうがいいかもしれない。それで10ラインくらいは稼げる。
一応デコード&画像化はできるので、マイコン側のプログラムはちゃんと動いてるはず。
まずは圧縮処理の時間を確認しなきゃいけない。ちゃんとパフォーマンスが出てれば、いよいよDMAのISRで圧縮して、1フレーム分キャプチャできるか!? という感じ。
処理時間の計測は、TIMを使えばキッチリ測れるので、いちいちオシロでパルス幅測って…みたいな面倒なことはしなくてもいい。まぁ、GPIOトグルするほうが簡単なので、大雑把な処理時間を測るだけならGPIOを使ったほうが楽なんだけど。
タイマでも、内部分周で2倍とか4倍とか8倍とかの計算ミスが発生する可能性があるから、結局大雑把にオシロなりロジアナなりで計測しておく必要はあるか。。
タイマは水平同期用とかADCトリガ用で初期化コードがあるので、分周比とか変えてやれば処理時間の計測ができるようになるはず。
あとは、データの破壊検出をどうにかしたいなぁ。検出したところで復元する方法はないんだけども。適当な間隔で加算レジスタリセットの符号を突っ込んでDC結合するって方法もあるが。まぁ、ちゃんと動いてる限りは量子化誤差とかは無いから、問題ないはず。
計算速度にある程度余裕があるなら、STM32のCRC計算機を使って、圧縮前のCRCを計算できる。確か32bitレジスタへのコピーだけで計算できるはずだから、1バイトあたり0.25命令を余分に追加するだけで処理できるはず。まぁ、16命令しか使えないうちの0.25命令だから、そんな余裕はないかもしれないが、無いなら無いでそもそも圧縮処理自体が成立しないはずなので。。
***
追記
G++の警告ってすげーんだな。ポインタ経由でアクセスした配列のインデックスを間違えて配列の一部を初期化せずに使ったら警告出してきた。そんなことしてるからコンパイル遅いんだよ……(おい
思いつく限りの最適化を施して、48KiBの圧縮に8.3msecくらい。
9Mspsだと48KiBのデータが5.5msec毎に出てくるから、圧縮が間に合わない。
「こうすれば早くなるかな」と思った変更でも、実際は遅くなったり、何が効くのかよくわからない。
ループ処理を減らすために4ブロックくらいまとめて処理すると、少し早く処理できる。一方で、16ブロックとかまとめると、逆に遅くなる。
デフォルトのmakefileでは-Ogだけど、試しに-O3にしたら5.8msecまで高速化できた。まだ足りないけど、もう少し。
試しにコンパイラを最新のものにしたら、ちょっと遅くなった。コードとの相性とかあるのかも。コンパイラルーレットやるか???(やらねーよ
ハフマンツリーはROMに入れてるけど、RAMに入れると微妙に早くなる。誤差レベルだけど。CCMRAMに入れるともう少し早くなる。誤差レベルだけど。
ADCサンプリングしながら処理する場合は、DMA転送が発生するから、ツリーだけでもCCMRAMに入れたほうが有利かもしれない。
あと少し、というところまでは来ているけど、あとどうやって改善していくか。。。禁断のオーバークロックに手を出すか?
あるいは、フロントポーチと水平同期パルスのキャプチャを行わない、とかもできるか。データ量が8%くらい減るので、ギリギリで間に合うかな、くらいにはなる。
もしくは、圧縮率を犠牲にして、差分を取るのをやめる、とか。背に腹は代えられないけど、メモリが足りなくなったら意味がないからなぁ。
もうちょっといろいろやってみよう。。。
せっかくNTSCのデコードがちゃんとできるようになってきたので、もうちょっと使いやすくしたい。
***
追記
ビット位置を数える変数をuint8_tからuint32_tに変えたら、5.8msから5.35msまで高速化できた。すげー効くな。
ARMコアは「ワードに対しては演算できるけど、ハーフワードとバイトに対しては演算できない」みたいな命令があるらしいので、その関係っぽい。
いままでuint_fast8_tとか効果あるのかよ、と疑ってたけど、かなり効果ありそうだなぁ。
0 件のコメント:
コメントを投稿