ラベル TOPPERS/ASPカーネル の投稿を表示しています。 すべての投稿を表示
ラベル TOPPERS/ASPカーネル の投稿を表示しています。 すべての投稿を表示

2011年10月29日土曜日

小規模組み込みシステム向けシェル・タスク『Natural Tiny Shell Task』が、TOPPERS活用アイデア・アプリケーション開発コンテストのアプリケーション開発部門で銀賞を受賞

小規模組み込みシステム向けシェル・タスク『Natural Tiny Shell Task』が、2011年度のTOPPERS活用アイデア・アプリケーション開発コンテストのアプリケーション開発部門で銀賞を受賞しました。




関連してET2011のTOPPERS/SESSAMEパビリオンにおいて、アプリケーションについてのショート・プレゼンテーションとデモンストレーションも予定しています。TOPPERS(や、その他RTOS)を使った小規模組み込みシステムでシェルのようなものが欲しいけど、あまり良い物が見つからないとお困りの方は是非御来場下さい。

詳しくはTOPPERSプロジェクト/ET2011のページを御覧下さい。

2011年4月12日火曜日

TOPPERSでスタック状況を確認するシステムコールを作る(quick-and-dirty)

概要

TOPPERS/ASPでアプリケーションを実装した後、やっぱり気になるのはスタックの状況です。
商用iTRONのツールの中には当たり前のようにあるスタック状況確認機能ですが、標準システムコールにはありません。

調べてみると非依存部にはスタックの先頭アドレスとサイズしかなく、依存部のタスクコンテキストブロックにスタックポインタがあります。
もしスタック状況を計算するようなシステムコールを標準として作りたいとすると、依存部に対する仕様(スタックポインタはXXXのように用意すること・・・のように。)が必要になるわけです。

スレッド型OSでスタック状況を確認できないのはなんとも気持ちが悪いものです。
そこで、今回はquick-and-dirtyでスタック状況を確認できるメカニズムを作ってみました。

動作

小規模組み込みシステムデバッグ用シェル - Natural Tiny Shell (NT-Shell)と組み合わせた場合の動作は以下のようになります。

>taskinfo
TSKID   STACK ADDR (HEAD:TAIL)  STACK USED (USED/TOTAL)
=========================================================
  1     0x10000b88:0x10000f87   132/1024
  2     0x10000f88:0x10001787   124/2048
  3     0x10001788:0x10001f87   108/2048
  4     0x10001f88:0x10002787   100/2048
  5     0x10002788:0x10002f87   204/2048
=========================================================

各タスクのスタックアドレスと使用量が一目瞭然で安心です。
上記の出力結果とプロセッサのメモリマップを見て「フムフム」と納得できます。


今回テストで動作させているシステムにはNXPセミコンダクターズのLPC1769が搭載されています。
このプロセッサの内蔵SRAMのアドレスにスタックポインタがあることがわかります。

inf_tskシステムコールを使う

inf_tskシステムコールを使うのは簡単です。
以下のようにタスクIDを指定してシステムコールを呼ぶだけです。

int i;
T_ITSK itsk;
syslog(LOG_NOTICE, "TSKID\tSTACK ADDR (HEAD:TAIL)\tSTACK USED (USED/TOTAL)");
syslog(LOG_NOTICE, "=========================================================");
for (i = 0; i < TNUM_TSKID; i++) {
    const int tskid = 1 + i;
    inf_tsk(tskid, &itsk);
    syslog(LOG_NOTICE, " %2d\t0x%x:0x%x\t%5d/%5d",
            tskid,
            itsk.stk_head, itsk.stk_tail,
            itsk.stk_used, itsk.stk_total);
}
syslog(LOG_NOTICE, "=========================================================");

inf_tskの実装

今回設計したシステムコールはinf_tskという名前です。(あー、そんな名前で作ちゃって!)
ref_tskを参考に実装を追加しました。

まず、include/kernel.hに定義を追加します。

extern ER inf_tsk(ID tskid, T_ITSK *pk_itsk) throw();

次に、システムコールで取得するデータを格納するための構造を用意します。

これもinclude/kernel.hです。

typedef struct t_itsk {
    PRI tsk_pri_curr; /* 現在のプライオリティ */
    PRI tsk_pri_base; /* ベースプライオリティ */
    SIZE stk_used;  /* タスクスタック使用量 */
    SIZE stk_total; /* タスクスタック総量 */
    void *stk_head; /* タスクスタック先頭アドレス */
    void *stk_tail; /* タスクスタック最終アドレス */
} T_ITSK;

ここにref_tskが持つタスク状態などを追加すると良いかもしれません。

次にシステムコール本体の実装を加えます。

今回は新たにtask_info.cというシステムコール実装用のソースを用意しました。
kernel/task_info.cがシステムコールの実装です。

/*
 * タスクの情報取得機能
 */

#include "kernel_impl.h"
#include "check.h"
#include "task.h"
#include "wait.h"
#include "semaphore.h"
#include "eventflag.h"
#include "dataqueue.h"
#include "pridataq.h"
#include "mailbox.h"
#include "mempfix.h"
#include "time_event.h"

/*
 *  タスクの情報取得機能
 */
#ifdef TOPPERS_inf_tsk

ER
inf_tsk(ID tskid, T_ITSK *pk_itsk)
{
    TCB *p_tcb;
    ER ercd = E_OK;
    uint_t tstat;

    p_tcb = get_tcb(tskid);
    t_lock_cpu();
    tstat = p_tcb->tstat;
    if (TSTAT_DORMANT(tstat)) {
        pk_itsk->stk_used = 0;
    } else {
        pk_itsk->stk_used = p_tcb->p_tinib->stksz
            - (p_tcb->tskctxb.sp - p_tcb->p_tinib->stk);
    }
    pk_itsk->stk_total = p_tcb->p_tinib->stksz;
    pk_itsk->tsk_pri_curr = EXT_TSKPRI(p_tcb->priority);
    pk_itsk->tsk_pri_base = EXT_TSKPRI(p_tcb->priority);
    pk_itsk->stk_head = p_tcb->p_tinib->stk;
    pk_itsk->stk_tail = p_tcb->p_tinib->stk + p_tcb->p_tinib->stksz - 1;
    t_unlock_cpu();

    return ercd;
}

#endif /* TOPPERS_inf_tsk */

後はMakefile.kernelにtask_info.cをコンパイルするような記述を追加してできあがりです。
実装をご覧になってわかる通り、p_tcb->tskctxbは依存部にあるタスクコンテキストブロックで、本来ここで参照してはいけません。

まとめ

今回の実装はTOPPERS/ASPから見ると「最悪」と言えます。
が、システムを実現する立場からすると「安心」が得られます。

スタックオーバーフローによってシステムが意味のわからない挙動になってしまっては、せっかくのRTOSを使った楽しい開発が台無しです。少しの機転でシステムの状態を視覚的に把握することができ、開発を少しでも楽にできれば嬉しいですよね?

謝辞

この実装はマイコン工作実験日記さんのアイデアに触発されています。
素晴らしいアイデアに感謝しております。

2011年3月2日水曜日

Natural Tiny Shell(NT-Shell)のポーティング事例。LPCXpressoとTOPPERS/ASPで小規模組み込みシステムの開発をもっと便利に!

はじめに

前回の記事でVT100仮想端末を小規模組み込みシステムで実現するためのライブラリを公開しました。
中には「これが何の役に立つのだろう?」と疑問に思われた方も少なくないでしょう。

この手のツールは実際の開発作業が進むにつれて利便性を再認識することが少なくありません。
(逆に言うと実際に開発作業で相当に困らないと不便な事に気付かない事が多いのです。)

今回はLPCXpresso上でTOPPERS/ASPを動作させるシステムを実際に開発するシステムと見立てて、Natural Tiny Shell(NT-Shell)をポーティングして活用した時のメリットについて御紹介します。


TOPPERS/ASPでNatural Tiny Shell(NT-Shell)を使う

今回はRTOS上にシェルを実装することでシステム開発をもっと便利にしてみましょう。
題して「LPCXpressoとTOPPERS/ASPで小規模組み込みシステムの開発をもっと便利に!」です。
小規模組み込みシステムでありがちな「この程度の規模だからいいや。」と諦めている方におすすめです。
きちんと動作するデバッグ用シェルがあるだけでシステムが見違えるように良くなったように感じます。
デバッグも楽しくなって作業効率が向上すること間違いなし!
是非皆さんも挑戦してみませんか?

エコーバックを行わないようにする

受信した文字列をエコーバックする設定を取り除く。

TOPPERS/ASPでは受信した文字列をエコーバックすることができるようになっています。
Natural Tiny Shell(NT-Shell)を使用する時、エコーバックは都合が悪いので設定を外します。
これはシリアルインターフェースドライバで行うことができます。

syssvc/serial.c の serial_opn_por 関数でIOCTL_ECHOの指定を取り除きます。
serial.cの240行目付近です。


/*
 *  変数の初期化
 *  エコーバックさせたい時にはIOCTL_ECHOを追加すると良い。
 */
p_spcb->ioctl = (IOCTL_CRLF | IOCTL_FCSND | IOCTL_FCRCV);


なぜ受信した文字列をそのまま返してはいけないかという話です。

システムに接続されたシリアル端末が送信してくるコードの中には制御コードが含まれる事があります。
今回のシェルを設計実装した目的の1つは「制御コードをうまく処理してシリアル端末ユーザに便利な機能を提供しよう」です。
受信したコードをそのまま送信した結果、シリアル端末上で制御コードが解釈されてしまっては従来と何も変わらない事になってしまいます。
これを避ける為にエコーバックをしないようにします。

例えば、「おっ。上方向キーだな。じゃあ、過去のコマンドを表示してあげよう。」といった具合です。

システム

今回のシステムは以下のようになっています。
実際に開発するシステムに見立てていると考えてみて下さい。


システムと開発用ホストは2つのUSBで接続されています。

1つはLPCXpresso用でこれはLPCXpresso上のデバッガに接続されています。
実際に開発するシステムによってはここは他のデバッガに置き換わる事もあるでしょう。

もう1つは開発対象システムのUARTをUSBで入出力するための変換器との接続です。
今回は秋月電子通商で販売されているFT2232Dを使った変換器を使用しました。

実際の接続した状態は以下のようになっています。


内部タスクの構成

今回の内部タスク構成を以下のようにしました。
  • task_ledblink: LEDを一定間隔でトグルするLED点滅タスク
  • task_ntshll: Natural Tiny Shellをフロントエンドとするシェルタスク

LED点滅タスクを作る

LED点滅タスクは一定時間間隔で動作しLEDの状態をトグルさせるタスクです。
点滅の間隔は100[ms]ですが、データキューから値を受け取って変化させることができるようにしてあります。
外部からデータキュー経由で点滅の速度(正確にいうとタスクの動作間隔)を変化させることができるようにしてあります。


void task_ledblink(intptr_t exinf)
{
    syslog(LOG_NOTICE, "task_ledblink: Started.");

    int ledspd = 100;
    while(1)
    {
        uint_t value;
        while (prcv_dtq(DTQ_LEDSPD, (intptr_t *)&value) == E_OK) {
            if (value > 0) {
                ledspd = value;
                // syslog(LOG_NOTICE, "new value is %d.", value);
            }
        }
        LPC_GPIO0->FIOPIN ^= ACTLED;
        tslp_tsk(ledspd);
    }
}


シェルタスクを作る

次にNatural Tiny Shell(NT-Shell)を組み込んだシェルタスクを立てます。
シェルタスクはUARTに対する入出力を管理しながら、ユーザの要求をシステムに伝達する役目を果たします。


void task_ntshell(intptr_t exinf)
{
    syslog(LOG_NOTICE, "task_ntshell: Started.");
    serial_opn_por(SIO_PORTID);

    ntshell_execute(&parser,
            &editor, &history,
            func_read, func_write, func_cb);
}


ntshell_executeは処理を戻さない関数です。
UARTからの入出力関数を受け取って処理を行ないます。

今回の例ではfunc_readは以下のようになっています。


int func_read(void *buf, int cnt)
{
    return serial_rea_dat(SIO_PORTID, buf, cnt);
}


同様にfunc_writeは以下のようになっています。


int func_write(const void *buf, int cnt)
{
    return serial_wri_dat(SIO_PORTID, buf, cnt);
}


ユーザが操作を決定するとコールバック関数(上記ではfunc_cb)が呼ばれるようになっています。
ユーザが入力を完了後、エンターキーを押した時の入力文字列が渡されるようになっています。

ここでユーザの要求に応じて処理を行えば良い事になります。


int func_cb(const unsigned char *text)
{
    // TODO 入力されたコマンドに応じて処理を行う。
}


ちなみに、この関数内部の実行スレッドはシェルタスクのスレッドです。
今回のアプリケーションでは以下のように実装してみました。
ntop_compareはNatural Tiny Shellに含まれるユティリティ関数で、文字列の比較を行うものです。


int func_cb(const unsigned char *text)
{
    static int ledspd = 100;
    if (ntopt_compare(text, "INTERVAL UP") == 0) {
        if (ledspd < 500) {
            ledspd++;
            snd_dtq(DTQ_LEDSPD, (intptr_t)ledspd);
        }
    } else if (ntopt_compare(text, "INTERVAL DOWN") == 0) {
        if (ledspd > 1) {
            ledspd--;
            snd_dtq(DTQ_LEDSPD, (intptr_t)ledspd);
        }
    } else if ((ntopt_compare(text, "HELP") == 0)
            || (ntopt_compare(text, "?") == 0)) {
        text_puts("\r\nINTERVAL UP   : Task interval time increase.");
        text_puts("\r\nINTERVAL DOWN : Task interval time decrease.");
    } else {
        if (ntopt_get_count(text) > 0) {
            text_puts("\r\nUnknown command found. (HELP: display help.)");
        }
    }

    return 0;
}


実際に使ってみる

実際に使用している様子を動画で御紹介します。


リソース

今回は3千円で楽しめるARMマイコンとRTOSの世界 (TOPPERS/ASP on LPCXpresso LPC1768)のプロジェクトに小規模組み込みシステムデバッグ用シェル - Natural Tiny Shell (NT-Shell)を追加する形で作業しました。
プロジェクトはここからダウンロードできます。

2011/03/08追記。
公開当初のサンプルプロジェクトが使用しているNT-Shellにはバックスペース処理にバグがありました。
修正したライブラリに差し替えました

まとめ

ターゲットに対して対話型で操作要求ができるとちょっとした確認をする時に非常に便利です。
今回はLPCXpresso(Cortex-M3搭載)でRTOS(TOPPERS/ASP)を動作させるという比較的小さな組み込みシステムでの応用例を示しました。

システム内部の値を外部から変更することは当然デバッガなどでも可能です。
しかし、ちょっとしたパラメータを変更したい場合や複数のパラメータを同時に変更したい時には不便です。

対話型のシェルインターフェースがあれば、開発ホスト並の利便性を確保することも可能になります。

補足

念の為補足しておくと、LEDの点灯間隔を変化させるという行為が主眼ではありません。
おそらく点灯間隔を変えるための実装にはもっと相応しいものがあるでしょう。

今回はあくまでシステム内部の挙動をシェルを介して変化させるというところに視点をおいてあります。
今回の実装では点灯間隔が狭くなるにつれてプロセッサの使用率も相当上がります。
システムがどの程度の負荷を許容するのかを外部でパラメータを変更させながら見ることもできるでしょう。

2010年7月22日木曜日

TOPPERS/ASPのコンフィギュレータをUbuntu 10.04上でコンパイルする

TOPPERS/ASPのコンフィギュレータをUbuntu 10.04上でコンパイルするには
  1. boostライブラリを予めインストールしておいて下さい。sudo apt-get install 'libboost*-dev'
  2. export LIBBOOST_SUFFIX=-mt; export BOOST_DIR=/usr/include/boostls

ビルドを行うと・・・

g++ -o cfg cfg.o cfg0.o cfg1.o cfg2.o cfg3.o ../toppers/itronx/libitronx.a ../toppers/libtoppers.a -lboost_filesystem-mt -lboost_program_options-mt
/usr/bin/ld: cannot find -lboost_program_options-mt
collect2: ld returned 1 exit status
make: *** [cfg] エラー 1

こんな感じでエラーが出るかもしれません。

ldconfig -p |grep boost_program_optionsでライブラリを確認します。

libboost_program_options-mt.so.1.38.0 (libc6) => /usr/lib/libboost_program_options-mt.so.1.38.0
libboost_program_options-mt-d.so.1.38.0 (libc6) => /usr/lib/libboost_program_options-mt-d.so.1.38.0
libboost_program_options-mt-d.so (libc6) => /usr/lib/libboost_program_options-mt-d.so

/usr/libに行ってsudo ln -s libboost_program_options-mt.so.1.38.0 libboost_program_options-mt.soでlibboost_program_options-mt.soへのシンボリックリンクを作成します。

これでコンフィギュレータのビルドは通ります。

2010年5月3日月曜日

TOPPERS/ASP on AVR

TOPPERS/ASPのポート済みデバイスにAVRが入っていないのは気に入らないということで移植を検討中なのですが、FreeRTOSを見た後にTOPPERS/ASPを見ると「複雑なのね」と感じてしまいます。
それぞれ理由があってそうなっているのはよくわかりますが、日本人の苦手な割り切り具合が露呈しているようにも思います。

矛盾するのですが魅力も感じます。
魅力はどこから来るかと言うと、技術的好奇心から来るものでしょう。

2009年10月10日土曜日

TOPPERS/ASPカーネル開発環境構築

■ダウンロード

 ▼TOPPERS/ASPカーネル ターゲット非依存部パッケージ(担当:名古屋大学)
asp-1.4.0.tar.gz (2009-05-11)
 ▼H8/300Hアーキテクチャ・GCC依存部パッケー ジ(担当:宮城県産業技術総合センター)
asp_arch_h8300h_gcc-1.4.0.tar.gz (2009-05-13)

■展開

 asp-1.4.0.tar.gzとasp_arch_h8300h_gcc-1.4.0.tar.gzを展開。

■環境

 ▼cygwinのインストール。
 developパッケージは全てインストール。
 PATHにcygwin\binを追加する。

 ▼configureでdllエラーが発生する問題
cd cygwin\bin
ash rebaseall

■コンパイル

 ▼configure
./configureとするとコンフィグ可能なターゲットが表示される。
./configure -T akih8_3069f_gccとする。

 ▼Executable file of the configurator (cfg) is not found.と言われる。
「実行可能なコンフィギュレータが見つからない。」
→そのままの意味。

TOPPERS/ASPカーネル

またまた興味が湧いてきた。
今使っているプロセッサ上で動かしてみたい。