PIC16FのためのリアルタイムOSという妄想

ミッドレンジマイコンでマルチタスクを書いていたら、黒歴史を思い出しました。私はPIC16FのためのマルチタスクOSをアセンブリ言語で開発してやろうと考えていた時期があるのです。

その目論見は、当然のことながらPIC16Fの絶対的なリソース不足の前にもろくも崩れ去りました。まあ、高性能CPUのためのオペレーティングシステムなら開発できるのかと言われれば、やはりそんな事はないのですが。


組み込みOSのリアルタイム性


パソコンの数値計算プログラムなどは、その処理速度が速ければ速いほど優れており、高速に計算を終えるため、かたやCPUの処理性能向上、かたやアルゴリズムの改良と地道な努力が続けられています。

一方で、組み込みマイコンプログラミングでは、処理速度が高速であること以上に、確実に所定の時間内に処理が完了することが重要視されます。
言い換えれば、一定時間以内に処理が完了することさえ確実ならば、早く終わらせてしまっても意味が無く、複数のタスクを処理している最中に高優先度のタスクの要求が発生したならば、「すぐに」処理が行われることに重点をおくことが多いと言うことになります。

この「すぐに」というのが「リアルタイム性」と言うことですが、当然ながら「本当に全く間をおかずに」処理を開始することなど不可能です。
そんなわけで、最高優先度のタスクが発生したら、最悪でもX秒以内にそのタスクを開始することを保証する、というのが現実的なリアルタイムOSの役割です。(このX秒の部分がオペレーティングシステムの処理による遅延です。当然短い方が優秀なOSと言うことになります。)

背景にある思想


他の処理をしている最中に、その処理を無理やり中断して別の処理を開始するためのメカニズムはPIC16Fに関しては割り込み以外ありえません。優先度の2段階以下であれば、メインルーチンと割り込みでうまく処理できること、3段階以上ならば多重割り込みが必要になることはミッドレンジマイコンでマルチタスクでも書きました。

PIC16Fは、多重割り込みをサポートする機能を有してはいませんが、割り込みルーチンの内部で、明示的に割り込みを許可することにより多重割り込みのようなことが出来ます。
この考え方を用いて、割り込みルーチンの中に優先度の順にフラグをポーリングするタスクスイッチャを実装すれば、多段階の優先度をサポートするオペレーティングシステムもどきが作れるはずです。

実装


未完成のコードを以下に示します。ファイルの更新日付を信じるならば、"main.asm"の最後の更新は2007年1月1日でした。2年半前の私は正月にもかかわらずご苦労なことです。

現状、人様に見せられる状態ではない上、たぶん、煮ても焼いても食べられません。しかし、これ以上、手をつけるつもりも全く無いので公開してしまいましょう。"macro.inc"のアスキーアートなど我ながら涙ぐましくもあります。



当然バグもたくさんあるでしょう。探す気も起きませんし、報告していただいてもなおす気も起きません。(それ以前に未完成ですが。)

動作に関して、タスクスイッチャの基本的な部分は、後閑哲也さんのPICROSをまねしようと思っていた記憶がかすかにあります。マクロとして定義してあるので、タスクの数だけ展開して使います。

クロック周波数や電源電圧等の回路定数を設定するためのインクルードファイル的なものもあったような気がするのですが、ハードディスクの中に見当たりませんでした。

何故かシリアル送受信は、内部モジュールを使わずにソフトウエアで実現しようとしていたようです。受信時に3入力の多数決をとるコードを書いたような気がするのですが、これも見つかりませんでした。

ひょっとしたら、発掘したソースコードは最新のものではないのかもしれません。

問題点


結論から書くと、PIC16Fは絶望的にRAMが足りません。

最初に限界を迎えるであろうことが予想されるリソースは、ハードウエアスタックでした。
なぜならば、システムの根幹を支えるのが擬似多重割り込みであり、割り込み1つに対してスタックを1つ消費するからです。
PIC16Fのハードウエアスタックは8段階までしかなく、PUSH/POPに類する命令が一切存在せず、プログラムからスタックに干渉する手段が無いため逃げ場もありません。

このハードウエアスタックをすべて割り込み(タスクスイッチャ)のために使うことを考えると、サブルーチンの戻り番地は他の汎用レジスタに保存する必要があります。そこで、汎用レジスタをソフトウエアスタックとして使うためのマクロをいくつか書き、CALL/RETURNの代用としてJUMP/BACKというマクロを書きました。

"charlcd.asm"や"7seg.asm"などはJUMP/BACKで書いたサブルーチンのサンプルです。

しかしながら、非割り込みサブルーチンの戻り番地をPICの汎用レジスタ(RAM)に保存するとしても、ハードウエアスタックが8段階しかないと言う事実は変わりません。また、スタック構造を実装したおかげで、汎用レジスタ(RAM)もどんどん使われてしまいます。
オペレーティングシステムの基礎の勉強などしたことが無い素人目にも、リソースの管理が必須であることは自明でした。

では、どうやってリソースを管理するか?セマフォ?メッセージ渡し?
リソースが足りないがために、リソース管理をしなければならないのに、そのリソース管理にリソースが必要なんて・・・と思ったあたりで、バカバカしさが限界を迎えました。

大切なのはバランス感覚


なんというか、「ぼくのかんがえたさいきょうのがんだむ」的な痛さ・恥ずかしさを感じます。肝心なのは目標を達成すること、そのために合理的な手法は何であるか考えること、そのことを見失ってはいけません。

ネット上の質問掲示板では、「出来る限り低ノイズの電源」だとか「限りなく低ひずみの発振器」だとか言う荒唐無稽な書き込みをよく見かけますが、これもその類です。頑張ったけど要求された性能を満たさなかったというのはあきらめるほかありませんが、要求された性能を過剰に超える性能のものを作っても疲れるだけです。

そう考えると、後閑哲也さんのPICROSはよく出来ています。本当に感心します。

さて、汎用的なオペレーティングシステムは誇大妄想でしたが、割り込みルーチン内でわざと割り込み許可を行う手法自体は有用です。電気自動車用データロガーもこの手法を用いればプログラムだけで3段階の優先度を処理できると思います。

最後に


最後になりましたがお礼を。ミッドレンジマイコンでマルチタスクで2009-09-01に非公開でコメントを下さった方、内容には触れませんが、ありがとうございます。

関連エントリ




参考URL




フィードバック



にほんブログ村 その他趣味ブログ 電子工作へ

 ↑ 電子工作ブログランキング参加中です。1クリックお願いします。


コメント・トラックバックも歓迎です。 ↓      


 ↓ この記事が面白かった方は「拍手」をお願いします。

tag: PIC 

PIC12/16F Software delay その3

PIC12/16Fでのタイマをつかわないソフトウェアでの一定時間の時間稼ぎプログラムの時間計算方法について。
20MHz動作でも10秒以上を設定できる3段階のネストまで拡張。


○ネストが3段階のとき
3段階までのネストで、システムクロックfOSC=20MHzの場合でも、10秒以上のdelayを作成することができます。これ以上の時間を消費させるアプリケーションでは、sleep等も検討すべきでしょう。

さしあたって、汎用レジスタの確保。
        udata   H'20'
TMP res D'3'


コード本体
        movlw   x
movwf TMP
movlw y
movwf TMP+D'1'
movlw z
movwf TMP+D'2'
LOOP
;xのネスト
decfsz TMP,F
goto LOOP
;yのネスト
decfsz TMP+D'1',F
goto LOOP
;zのネスト
decfsz TMP+D'2',F
goto LOOP


(a) zとyのネストについて
ネストが2段階のときまでの考察より、それぞれ(3z-1)サイクルと{(3y-1)+767(z-1)}サイクルとなります。

(b) xのネストについて
最初の1順は、(3x-1)サイクル、それ以降は1順あたり(3*256-1)サイクルかかります。
yのネストは、z回実行され、そのうちの(z-1)回はxのネストを256回必要とします。残りの1回は、xのネストをy回必要とします。

よって、xのネストの実行回数は(z-1)*256回。前述のとおり、xのネストは最初の1回のみ(3x-1)サイクル、それ以降は(3*256-1)サイクルとなるので、xのネストの実行サイクルは

(3x-1)+(3*256-1)*{(z-1)*256+y-1}

x,y,zのネストと代入の6サイクルをあわせて

197122z+770y+3x-197883サイクル

となります。

tag: PIC アセンブラ 

PIC12/16F Software delay その2

PIC12/16Fでのタイマをつかわないソフトウェアでの一定時間の時間稼ぎプログラムの時間計算方法について。
少し長い時間を設定できるネストを2段階まで拡張。


○ネストが2段階のとき
769cycleよりも長いディレイが必要な場合は、ソースのネストを深くして対応します。ネストひとつにつきひとつの汎用レジスタを消費します。

さしあたって、汎用レジスタの確保。
        udata   H'20'
TMP res D'2'


コード本体
        movlw   x
movwf TMP
movlw y
movwf TMP+D'1'
LOOP
;xのネスト
decfsz TMP,F
goto LOOP
;yのネスト
decfsz TMP+D'1',F
goto LOOP


ここで、LOOPに続く1回目のdecfszとgotoのペアを「xのネスト」と名づけます。同様にその次のdecfszとgotoのペアを「yのネスト」と呼ぶことにします。(ネストという言葉の使い方が一般的なものと少しずれていますが、気にしない方向で。)

(a) yのネストについて
PICの命令実行順序のとおりに考えると分かりにくいですが、yのネストに存在する2つの命令が実行される回数は、(xの値にかかわらず)yの値だけで決まります。yのネストの実行サイクル数は

(a-i) decfszは必ず1回だけスキップを実行 : 2 cycle
(a-ii) decfszは(a-i)以外は1cycle : y-1 cycle
(a-iii) gotoは(a-ii)と同じ回数×2cycle実行 : 2(y-1) cycle
(a-i)~(a-iii)を合計して : 3y-1 cycle

(b) xのネストについて
xのネストは最初の1順のみTMPにxが代入された状態から1周し、その後はTMPにD'0'が入った状態、すなわちx=256の状態からの実行となります。

(b-i) 最初の1順は、ネストが1段階のときの考察から : 3x-1 cycle
(b-ii) 2順目以降は(3*256-1)cycle、(y-1)繰り返すため : 767(y-1) cycle
(b-i)(b-ii)を合計して : 3x+767y-768 cycle

(a)(b)および代入部分の4cycleを合計して : 3x+770y-765 cycle

tag: PIC アセンブラ 

PIC12/16F Software delay その1

PIC12/16Fでのタイマをつかわないソフトウェアでの一定時間の時間稼ぎプログラムの時間計算方法について。
考え方の基本となる、ネストが1段階の場合まで。


○ネストが1段階のとき

さしあたって、汎用レジスタの確保。
        udata   H'20'
TMP res D'1'


コード本体
LOOP
decfsz TMP,F
goto LOOP


汎用レジスタTMPは8bitなので、符号なし整数でD'0'~D'255'まで扱えますが、ディレイが最大になるのは、最初にTMPにD'0'を代入したときです。それ以外では、D'255',D'254',・・・,D'1'の順にディレイが短くなります。D'0'のときはD'256'と考えると

TMPの初期値がxであるとき、LOOPの実行サイクル数は

(i) decfszは必ず1回だけスキップを実行 : 2 cycle
(ii) decfszは(i)以外は1cycle : x-1 cycle
(iii) gotoは(ii)と同じ回数×2cycle実行 : 2(x-1) cycle
(i)~(iii)を合計して : 3x-1 cycle

        movlw   x                       ;1 cycle
movwf TMP ;1 cycle
LOOP
decfsz TMP,f
goto LOOP ;3x-1 cycle


合計すると'''3x+1 cycle'''となる。

1≦x≦256なので、
delay(max)= 3*256+1=769 cycle
delay(min)= 3*1+1=4 cycle

○cycle数と実時間の相互変換
PICの動作クロックをFOSC[Hz]とし、t[s]のソフトウェアディレイを作る場合の実行サイクル数nは以下のように求められる。

PICは、1cycleに4clockを要するので1cycleにかかる時間は

4/FOSC [s]

よって、t[s]のディレイに必要な実行サイクル数nは

n=t/(4/FOSC)=(t*FOSC)/4

4≦n≦769の条件を満たす場合、1段階のネストで実装できます。nからxをもとめるには、n=3x+1をxについてとけばよいので

x=(n-1)/3

端数はNOPで調整します。

tag: PIC アセンブラ 

MPLABで外部エディタをつかう

MPLAB IDE ver 8.15から外部エディタが利用可能になったようです。


air_variableさんのページの掲示板PICについて語ろうPart2のair_variableさんの書き込みによると


52 :air_variable:2008/11/01(土) 22:50:10
MPLAB8.15より、外部エディタが使用可能になりました。
秀丸などの日本語エディタが使用できるので、それらになれている人であれば便利な機能です。

設定方法は、mplabのメニューバーより
Configure → SettingsのExternal Editorタブで Use External Editerのチェックを入れ、External Editor EXE Pathの欄にはエディタソフトの実行ファイルをフルパスで指定します。例えば秀丸エディタなら C:\Program Files\Hidemaru\Hidemaru.exe
と設定すればokです。設定後プロジェクトウィンドウ内のソースファイルをダブルクリックすれば、指定されたエディタで開かれます。
FC2カウンター
カテゴリ
ユーザータグ

LTspiceAkaiKKRmachikaneyamaScilabKKRPSoC強磁性OPアンプPICCPA常微分方程式モンテカルロ解析ecaljodeトランジスタ状態密度インターフェースDOS定電流スイッチング回路PDS5022半導体シェルスクリプトレベルシフト乱数HP6632AR6452AI2C可変抵抗分散関係トランジスタ技術ブレッドボード温度解析反強磁性確率論バンドギャップセミナー数値積分熱設計非線形方程式ソルババンド構造絶縁偏微分方程式ISO-I2CLM358フォトカプラ三端子レギュレータカオスLEDシュミットトリガGW近似A/Dコンバータ発振回路PC817C直流動作点解析USBマフィンティン半径数値微分アナログスイッチTL43174HC4053カレントミラーサーボ量子力学単振り子チョッパアンプ補間2ちゃんねる開発環境bzqltyFFT電子負荷LDAイジング模型BSch基本並進ベクトルブラべ格子パラメトリック解析標準ロジックアセンブラ繰り返し六方最密充填構造SMPコバルトewidthFET仮想結晶近似QSGW不規則合金VCAMaximaGGA熱伝導cygwinスレーターポーリング曲線キュリー温度スイッチト・キャパシタ失敗談ランダムウォークgfortran抵抗相対論位相図スピン軌道相互作用VESTA状態方程式TLP621ラプラス方程式TLP552条件分岐NE555LM555TLP521マントル詰め回路MCUテスタFXA-7020ZR三角波過渡解析ガイガー管自動計測QNAPUPSWriter509ダイヤモンドデータロガー格子比熱熱力学awkブラウン運動起電力スーパーセル差し込みグラフ第一原理計算フェルミ面fsolveCIFxcrysden最大値最小値ubuntu最適化平均場近似OpenMPシュレディンガー方程式固有値問題井戸型ポテンシャル2SC1815TeX結晶磁気異方性OPA2277非線型方程式ソルバフラクタルFSM固定スピンモーメントc/agnuplotPGA全エネルギーfccマンデルブロ集合縮退正規分布キーボード初期値interp1multiplotフィルタ面心立方構造ウィグナーザイツ胞L10構造半金属二相共存ZnOウルツ鉱構造BaOSIC重積分磁気モーメント電荷密度化学反応クーロン散乱岩塩構造CapSenseノコギリ波デバイ模型ハーフメタルRealforceフォノンquantumESPRESSOルチル構造スワップ領域リジッドバンド模型edelt合金等高線凡例軸ラベル線種シンボルトラックボールグラフの分割MAS830LPIC16F785トランス入出力CK1026PC直流解析パラメータ・モデル等価回路モデル不規則局所モーメント関数フィッティング日本語ヒストグラムTS-112ExcelGimp円周率TS-110LMC662片対数グラフ三次元specx.fifortUbuntu文字列疎行列不純物問題ジバニャン方程式ヒストグラム確率論マテリアルデザインP-10境界条件連立一次方程式AACircuit熱拡散方程式HiLAPW両対数グラフ陰解法MBEナイキスト線図負帰還安定性Crank-Nicolson法EAGLE最小二乗法

最新コメント
リンク

にほんブログ村 その他趣味ブログ 電子工作へ