田舎の組み込みプログラマーがわざわざ趣味でも色々開発してみようとあがく様を綴るブログです。
DMM.makeのクリエイターズマーケットに出品しています。

2000h問題、部分的に解決2015年09月08日

2000h問題とは

寡聞にして知らなかったのですが、R8Cでは絶対ビット命令アドレッシングで使用できるメモリの上限は1FFFhまでとなっています。

R8CのCAN関連レジスタは2E00h以降に割り付けられており、この制限に引っかかっていることに遅ればせながら気付いて先日つまづいてしまったわけです。

そこで

部分的にですが、以下のような処方で解決を図ってみました。
ちなみに、言語は構造化アセンブラです。

; 定義部
slpm_c0ctlr .define 2,c0ctlr

MEM$_BIT_RESET .macro iBitNum, iBaseMem
    .if iBaseMem < 2000h
        bclr iBitNum, iBaseMem
    .else
        A0 = iBitNum
        bclr iBaseMem[A0]
    .endif
.endm

; 実体記述部
MEM$_BIT_RESET slpm_c0ctlr

; 展開結果
MEM$_BIT_RESET 2,c0ctlr
.if iBaseMem < 2000h
.else
    A0 = 2
    MOV.W    #2,A0
    bclr c0ctlr[A0]
.endif

ざっくり言うと、2000h以降のビット操作命令に関しては自動的にアドレスレジスタ相対アドレッシングにしてしまうと言うわけです。

定義部の".define"ではビット情報を文字列として定義しています。
ビット定義には".btequ"という専用の疑似命令があるんですが、これはアセンブル時にアドレスの決まっているメモリにしか使用できず、実質的にはSFR領域にしか使用できません。

そこで、単なる文字列として定義しておけばリロケータブル領域の変数に対してもビット定義をしている体を為すことができるのです。

構造化アセンブラについて語り出すと長くなるのでこの辺で。

マージンを調整しました2015年09月09日

今使っているブログデザインはマージンが広すぎるように感じましたので調整してみました。

こういう時はFirefoxアドオンのFirebugが便利ですね。
気になる要素を選べば効いているCSSが表示されるだけではなく、試しに変更してみることもできる素晴らしさ。

そこで十分調整してからアサブロのCSSを変更すればとてもスマートに更新できます。

そういえば自分の会社のウェブページを随分長い間更新していませんが、作った時にはスタイルシートの調整でどえらい苦労をしたものでした。
今なら当時に比べて色々楽にスピーディーにできそうですし、IE6対策ももう時効ですよねって、どんだけ更新してないんだよって話ですね。

構造化アセンブラもカテゴリーに2015年09月09日

なんだか

構造化アセンブラについてもっと語りたくなってしまったのでカテゴリーを追加してみました。

先日の"MEM$_BIT_RESET"マクロは、よく考えてみるとリロケータブル領域のビットには使えませんし、通常の2000hより上位アドレスにある SFRのビットは".btequ"で定義されているのでこれまた使えずと、どや顔で紹介した割にはほとんどCAN部分専用という感じでした。

そこで

今回はもう少し使えそうな記述をご紹介します。

; 定義部
CAN0_MODE        .define    "[ c0str ].b & 11b"
CAN_OPERATION    .equ    00b
CAN_RESET        .equ    01b
CAN_HALT         .equ    10b

; 実体記述部
    for CAN0_MODE != CAN_OPERATION
    next

; 展開結果  
..fr0009:
    MOV.B    c0str,R0L
    AND.B    #11b,R0L
    CMP.B    #CAN_OPERATION,R0L
    JEQ    ..fr000b
    JMP    ..fr0009
..fr000b:

CANモジュールのモードがオペレーションモードに切り替わるのをfor文で待つ処理です。
条件は"=="も使えますし、do文やif文もありです。

こんなのはCでは当たり前の記述じゃないかと思われるかもしれませんが、アセンブラにこの記述を織り交ぜられるところがいいんです。

とまぁ、こんな感じで時々構造化アセンブラをごり押ししていこうと思います。

Vport with Power で行こう2015年09月14日

製品では

コネクターの刺し間違いを防止するためにあえてコネクターの種類やピン数、色などをバラバラにしたりしますが、開発段階では統一しておいた方が色々手早く出来そうです。

そこで

Vport with Power規格というのに乗っからせてもらうことにしました。

詳しいことは公式ページであるブイポートラボを見ていただくとして、ざっくり言うと、MIL規格10Pコネクタの9番ピンをGND、10番ピンをプラス電源として、残り8ピンをI/Oとして使うというものです。

インターフェイス基板をVportde

写真の上側はタクトスイッチ4点、トグルスイッチ2点、ロータリーエンコーダ1個のスイッチ入力基板で、下側は照度センサ、湿度センサ、温度センサ、2軸ジャイロセンサ、3軸Gセンサのアナログセンサ基板です。

ハーネスはご覧のようにフラットケーブルを使い、このくらいですとプライヤーで簡単に圧着できますのでハーネスの作成も大幅に省力化できます。

なんだか

亀の歩みでなかなかCANモニターにたどり着けませんが、ハードやソフトの資産作りも大切なことですので着実にやっていこうと思います。

とは言っても、スケジュールが全くないとだらけてしまいがちですので、シルバーウィークには車のCANを覗き見ることを目標にテンションを上げていこうと思います。

位相計数モードで楽々カウント2015年09月16日

あると便利

あると便利なロータリーエンコーダ

ロータリーエンコーダはとても優れた操作性を持つ一方、プログラミングは面倒臭そうです。
しかし、マイコンが「位相計数」という機能を持っていれば簡単に処理できる模様。

幸いR8Cにもこの機能がありますのでその恩恵に預かれます。
ただし、少ピンの品種ではこの機能が省かれていたりしますので、ロータリーエンコーダを使う場合はタイマRG機能のある物を選ぶといいでしょう。

楽々設定

位相計数機能を使うにはロータリーエンコーダの信号をTRGCLKA端子とTRGCLCB端子に入れてやる必要があります。

そして、タイマ端子選択レジスタ(timsr)のb6とb7をONにしてこれらの端子機能を有効にします。
タイマモードを位相計数モードにしただけでは端子機能は有効にならないので注意が必要です。また、端子機能の設定はタイマを動作させる前に済ませておきましょう。

次にカウントアップ/ダウンの条件を設定します。

タイマRGカウント制御レジスタ(trgcntc)の上位4bitがカウントアップ条件、下位4bitがカウントダウン条件となっていますが、単純なロータリーエンコーダの場合はそれぞれどれか1bitをONしておけばいいようです。
これらをうまく設定することでもっと複雑なエンコードをするエンコーダにも対応できるということだと思います(たぶん)。

あとはタイマRGモードレジスタ(trgmr)でタイマモードを「位相計数モード」にし、カウントを開始すればロータリーエンコーダの操作に呼応してタイマRGカウンタ(trg)の値をアップ/ダウンしてくれます。

かなりお手軽ですね。

ただし

これだけだと単純にカウンタのアップダウンをしてくれるだけで、割り込みをかけたいとかいう場合にはあれこれ設定が必要なようです。
その辺りのことはデータシートの位相計数モードの項には書かれていないのでちょっと面倒臭そう。

と言っても、タイマRGカウンタをポーリングするだけでも当面は大丈夫だと思いますのでその辺りの追求は後回しにするかもしれません。

あと、エンコーダからの入力パターンに対してカウントのアップダウン方向を変えることはできませんので、希望した方向と違う場合にはハード側で対応する必要があります。

接続を入れ替えてもいいのですが、入力の安定性を考えて反転付きのシュミットトリガやフリップフロップを入れる方がいいかもしれません。

ハードは堅実に

ハードは今絶賛学習中ということもあり、まずはロータリーエンコーダをマイコンに直結してみました。
あ、もちろんプルアップはしてあります。

オシロで見ると存外きれいな波形です。
巷のロータリーエンコーダの解説では分からなかったんですが、クリック感のあるタイプでは停止位置だと両方オープンになっているようですね。

フィルタなしのロータリーエンコーダ波形

これならそのままでもいけるかもと思ったんですが、マイコンのカウント値を確認すると操作感と全く一致せず・・・。
で、さらに波形の観察をしているとこんな状態になることも。

ロータリーエンコーダのチャタリング

そこでウェブの情報を頼りにCRフィルタの値を決めてみました。
ロータリーエンコーダをゆっくり操作した時はきちんとカウントできたので喜んだのも束の間、が〜〜〜〜っと回すと全然だめでした。

オシロで見ると一目瞭然。
参考にしたのは押しボタンスイッチに対するフィルタですので、ロータリーエンコーダに使うには時定数が大きすぎました。

フィルタの効き過ぎたロータリーエンコーダ波形

フィルタの要素をあれこれ試すのは面倒そうだったので、とりあえずプルアップ抵抗を替えてみた結果がこちら。

かろうじて取りこぼしのないロータリーエンコーダ波形

まだ効き過ぎてはいますが、取りこぼしはなかったので当面はこれで行こうと思います。

そう言えば、今使っているカーオーディオのヘッドユニットはロータリーエンコーダの取りこぼしが酷いんですが、こういうことなのかもしれないと思ってみたり。
これまではソフトの処理がまずいんじゃないかと考えていたんですけどね。

職場では何でもソフトのせいにされると嘆いていたんですが、自分でも同じ事をしていたとは・・・。

実践!ロータリーエンコーダ2015年09月17日

このところ

あると便利なロータリーエンコーダ

ずっとロータリーエンコーダ関連の処理に取り組んでいて、先日ようやくR8Cのタイマ機能を使って取り込むところまで進みました。

今回はいよいよアプリケーションの中でどう使うかを追求します。

その前に

先日は入力のCRフィルターが効き過ぎていたのを放置していましたが、やはりそれでは勉強にならないと考えて調整してみました。
と言っても、コンデンサを0.1uFから0.033uFに変更しただけですが。

その結果がこちら。

フィルタ調整後のロータリーエンコーダ波形

昨日とほぼ同じ速さですが連続検出中もほぼ5Vまで戻っています。
わずか60msec足らずの間に15カウントした結果ですので十分だと思います。

そして、指先一つで速度自在なロータリーエンコーダはやはり便利なデバイスですね。

システム化

まず、R8Cの位相計数モードの設定はこんな風にしてみました。

;-----------------------------------
; タイマRG
;-----------------------------------
TRG$_MDF_MODE 00010001b           ; 位相計数モード[ 加算/減算条件 ]
TRG$_START                        ; カウント開始

マクロの中身は公開できませんが、先日ご紹介した位相計数モードの使用準備がこれだけでできるようにしてあります。

そして、いきなりですがロータリーエンコーダの処理部分がこちら。

;-----------------------------------
; メモリ定義部
;-----------------------------------
DIFFERENCE$_ALLOC rotary
char_num:    .blkb    1

;-----------------------------------
; 初期化部
;-----------------------------------
    DIFFERENCE$_INIT rotary, [trg].w
    [ char_num ] = 'A'
    LCD$_POS 0, 0
    LCD$_WRITE [char_num]

;-----------------------------------
; メインループ
;-----------------------------------
MAIN_LOOP$
    DIFFERENCE$_EXEC$_ rotary, [trg].w
        [ char_num ] = R0L + [ char_num ]
        LCD$_POS 0, 0
        LCD$_WRITE [char_num]
    _$
_END

本当にいきなりですが、LCDに1文字表示していて、その文字をロータリーエンコーダで切り換えていると書けば何となくお分かりいただけるのではないでしょうか。

"DIFFERENCE"は変化分を抽出するオブジェクトで、今回新設しました。
"[trg].w"はタイマRGのカウント値が入っているレジスタで、これを直に指定するのは隠蔽が不十分な感じですが、位相計数モードのためだけにこの手の処理を作るのも特化しすぎな気もするのでこれでよしとしておきます。

"DIFFERENCE$_EXEC$_"〜"_$"はメインループの中にありますので最短周期で実行されていて、"[trg].w"が変化した時だけブロックの中まで入っていくようになっています。
この時、R0には変化分がワードサイズで入っていますが、ブロック中ではR0Lで下位バイトだけ使っています。
このフリーダムさもアセンブラの魅力ですね。

とまあ、こんな風に構造化アセンブラにどっぷり浸っていますので他のマイコンが使えなくて困っていたりもします。
ちなみに、上記のソースは構造化アセンブラを使って筆者がこう書いているだけで、構造化アセンブラ自体に"MAIN_LOOP$"とかがあるわけではありません。

割り込みを使わなかったわけ

色々考えてみましたが、R8CのタイマRGの割り込みは位相計数モードでは実質アウトプットコンペアだけで、1カウント毎に割り込みをかけたかったら現在のカウント値の+1と-1の値で割り込みがかかるようにその都度セットする必要があり現実的ではありません。

それに、ロータリーエンコーダの処理はカウント毎に実行しないといけないわけでもなく、例えば100msec周期でチェックしてその間に30カウント増えていたとしたら30カウント分増えた処理をしてやればいいだけです。
カウントはタイマRGがキッチリやってくれていますので、周期はもっと長くても平気です。

とは言え、さすがにそれでは操作に違和感があるでしょうから、実際は10msecくらいが妥当でしょうか。
オシロで見たところ、相当速く回しても10msecだと4カウントまでいかないくらいでしたし。

というわけで、やっとロータリーエンコーダを使いこなすことができたと思います。