アナログフロントエンドの実験
最終的には基板を作る予定だが、事前に実験を行い、定数を決めたりしなければならない。
とりあえず、入力アンプ、レベルシフター、カップリングと DC 結合などを実験してみた。
LTSpice でも、多少シュミレーションをしている。
とりあえず、手元にあったオーディオ用 OPA2134 を使ったが、スピードが少し足りないように思う。
それでも、この OP アンプは安い割には超高性能で CP が高いと思う。
計測器のフロントエンドに使うような高速で、SN が高く、ローノイズ、高入力インピーダンスとなると、値段が高い・・
サンプリングが 2MHz 程度なので OPA2134 でも十分な気もする・・
とりあえず、JDS6600 オシレータの波形を入れてみた。
周期は、問題無く正確だ、電圧は計算とかなり違う。
次に、MTU で作った 10KHz の矩形波を使って、各ポイントを計測してみた。
SIGLENT のオシロスコープで観測すると、インピーダンスのマッチングが取れていないようだ・・・
まずはそれを合わす事から・・
DSO で使うプローブは、50MHz 対応の物で 1X、10X 切り替え式だが、回路構成の都合で 10X は使わない予定。
※だったが、やはり、対応は必須なのかもしれないので、構成などを再考している・・
インピーダンスを合わすのは意外と難しい・・・
フレームバッファをダブルバッファにする
シュミレータでは、ダブルバッファ(トリプルバッファ)なので、問題ないが、実機で操作すると、描画時間との関連で、リアルタイムな描画で問題が起こる。
これを解決するには、フレームバッファをダブルバッファにして、描画用と表示用でフリッピングを行う必要がある。
この仕様にすると、RX65N では、別の方法を考えなければならないが、RX72N の場合、潤沢にメモリがあるので問題は無い。
※RX65N では、ダブルバッファ構成にする余分なメモリが無い・・・
※これから購入する人は、あえて RX65N を買う人はいないだろうから、RX65N は切っても良いかもしれない。
簡単なコードを glcdc_mgr クラスに突っ込んで実験したが、思ったように動作せず、大きくはまった・・・
単純な勘違いが重なって、悩んだが、何とか思った動作が出来るようにはなった。
ただ、元々、シングルバッファで運用しようと設計していた部分を大きく変更しなければならず、しばらく改修が続いた。
その過程で、他のアプリも、DRW2D で描画出来るように drw2d_mgr クラスを改修した。
widget 管理は、シングルバッファでの運用を考えて実装してあるので、ダブルバッファにした場合にどうするか・・
これも、widget クラスに機能を追加して、ダブルバッファ対応に改修した。
波形の描画などをダイナミックに行うには、ダブルバッファは必須だ・・・
DRW2D エンジンを利用
ダブルバッファにすると、基本的に、常に描画する方向なので、DRW2D エンジンを積極利用する方が良い。
普通に考えて、描画はソフトで行うより高速だろうと思う。
また、DRW2D エンジンでは、線の太さや、アンチエリアスも簡単に出来る。
ただ、資料が少ないので、フラグの効果や、描画パラメーターの効果については、試すしか無い。
ビットマップテクスチャーを描画する(主にフォント)のに悩んだ。
普通に描画するのは直ぐに出来たけど、ビット「0」の部分を描画せずに透過させたい・・
で、やっと判った・・
//-----------------------------------------------------------------//
/*!
@brief ビットマップイメージを描画する
@param[in] pos 開始点を指定
@param[in] img 描画ソースのポインター
@param[in] ssz 描画ソースのサイズ
@param[in] back 背景を描画する場合「true」
*/
//-----------------------------------------------------------------//
void draw_bitmap(const vtx::spos& pos, const void* img, const vtx::spos& ssz, bool back = false)
noexcept {
if(img == nullptr) return;
const uint8_t* src = static_cast<const uint8_t*>(img);
int16_t w = ssz.x;
int16_t h = ssz.y;
// setup_();
d2_color clut[2];
clut[0] = back_color_.rgba8.rgba;
auto copyflag = d2_bf_filter;
if(!back) {
clut[0] &= 0xffffff;
copyflag |= d2_bf_usealpha;
}
// d2_setalphaex(d2_, 0, 0);
clut[1] = fore_color_.rgba8.rgba;
d2_settexclut_part(d2_, clut, 0, 2);
d2_setblitsrc(d2_, src, w, w, h, d2_mode_i1 | d2_mode_clut);
d2_blitcopy(d2_, w, h,
0, 0, w * 16, h * 16, pos.x * 16, pos.y * 16, copyflag);
}
Widget 関係のケア
widget_director では、描画は、変更が必要な場合にだけ行うようにしている。
※描画はやはりコストが大きいので、必要な場合にしか行わないようにしている。
そこで、機能を追加して、描画が起こった事を検出して、それを次フレームに持ち越して再描画を行うようにした。
こうすると、両方のフレームが常に同じ状態に保たれる。
「refresh()」では、内部的に特殊なフラグを設けて、「refresh」で描画した場合に、描画ステートを残さないようにした。
widd_last_ = widd_.update();
// ダブルバッファ時の widget 管理のケア
if(render_.is_double_buffer()) {
if(!widd_last_) {
widd_.refresh();
}
}
破線の描画
点線などを描画する場合など
※この API は利用方法が意外と難しく、かなり苦労した・・
※サンプルコードが無いので、ドキュメントを観ながらだったが、各 API がどのように機能するのか不明だった。
その為、色々試して、ようやく理解した。
とりあえず、縦、横にラインを引く場合のみサポートした。
斜めに引く場合、「d2_setpatternparam」で、方向ベクトルを設定する必要がある。
void setup_stipple_(const vtx::spos& d)
{
if(stipple_ != 0xffffffff) {
d2_setpatternsize(d2_, 8);
// d2_setpatternalpha(d2_, 0, 255);
// d2_setpatternalpha(d2_, 1, 255);
d2_setpatternparam(d2_, 0, 0, d.x, d.y);
d2_setpattern(d2_, stipple_);
d2_setfillmode(d2_, d2_fm_pattern);
}
}
短径領域の転送
フレームバッファ内で、短径領域をコピーするのも DRW2D で出来る。
//-----------------------------------------------------------------//
/*!
@brief 移動
@param[in] src ソース位置と大きさ
@param[in] dst 転送位置
*/
//-----------------------------------------------------------------//
void move(const vtx::srect& src, const vtx::spos& dst) noexcept
{
d2_utility_fbblitcopy(d2_, src.size.x, src.size.y, src.org.x, src.org.y, dst.x, dst.y,
d2_bf_filter);
}
まとめ
今回は、ダブルバッファ関係と、DRW2D 関係のケアで、終止して、アナログフロントエンドをケア出来なかった・・
それでも、DRW2D の本格移行が出来た感じで、それはそれで大きい。