2012年10月8日月曜日

TOPPERS/ASP for LPCにおける複数UART対応コード(の誤ち)

ほぼ名前だけのメンテナー(私)による改悪

TOPPERS/ASP for LPCとは、酔漢さんがホストされているTOPPERS/ASPのNXPセミコンダクターズ社向けプロセッサへのポートです。

私はほぼ名前だけのメンテナーですが、過去にコミットした私のコードでちょっと良くない点があったので御紹介します。普通はこういう事は書かないのですが、何を考えてそうして、何が良くなかったのかを示してみたい衝動にかられました。

さて、問題のコードはTOPPERSの中でも悪名高きUARTに関連する箇所です。
オリジナルのtarget_config.cは以下のようになっていました。


SIO_PORTIDを参照して必要なコードを生成させるという記述です。
ちなみにPINSELは以下のようなマクロです。


シリアルポートは「ひとまずシステム唯一」という仮定を用い、ここでよろしくやってくれるわけです。
加えて、「使いたいポートと違ったらアプリケーション・プログラマがよろしくやってくれ!」と主張しています。

私はここでちょっと「え?」と思いました。
「イマドキの人」にそういうのって通じるの?という具合です。

ここから私の余計なお世話が始まりました。
まずはSIOポートの初期化です。

デフォルトでパワーオンされていないペリフェラルに対してパワーオンが必要です。
また、同じTXDやRXDであっても、割り当て可能なピンが幾つか存在します。

「一行記述を見れば何が割り当てられているのかわかるのが親切というものではないか!」という主張を基に、以下のような実装に改悪しました。


で、それらのマクロは以下のようにしました。


これでアプリケーションプログラマが「おや?私の使いたいピンと違うぞ!」と直ぐに気付く事ができるし、加えて予めマクロが全てのパターンで用意されているので差し替えるだけで準備オッケイ!と相成ります。

こりゃ便利だなんて思うわけです。

さて、何が改悪なのでしょうか?
一見便利になったように見えますが、実は壮大な問題が含まれています。

改悪による壮大な問題

さて、先ほどのコード、パッと見は良いのですが、オリジナルにない修正を加えています。
  1. SIO_PORTIDを参照して初期化するのではなく、SIO_BAUD_RATE_PORTNを見て初期化。
  2. target_uart_initの呼び出し。
さて、SIO_PORTIDを参照して初期化する場合、該当するある一つのシリアルポートのみが初期化されます。実はとあるプロジェクトで「複数のUARTポートを同等に扱いたいなぁ」と考えていました。
これが最初の改悪の動機になりました。

「SIO_BAUD_RATE_PORTNが定義されていたらそのシリアルポートを使う!」で良いんじゃない?
それって凄く便利かも~!です。

一見良さそうですが、他のポートは依然「SIO_PORTIDを参照して初期化」を期待しています。
先の改悪のコードは一切「UARTを初期化しない」というおかしな挙動を生む原因になります。

加えてtarget_uart_initの呼び出しです。
この関数はpdic/uart/uart.cの関数を呼び出しています。

「あれ?pdicって抽象化されたデバイスドライバだよね?」とはたと気づくわけです。
要するにここで行なっているのは、下層から上層への呼び出しという、主従関係が逆転する極めて重大な問題というわけです。

というわけで・・・

というわけで私の浅はかな判断により改悪したコードによって、メインコミッタである酔漢さんにご迷惑をおかけした次第です。
LPC1830を試す(3)でサラッと触れてありますが・・・。恐ろしくて真相は聞けません。

2 件のコメント:

  1. ポートの設定はどこでやるべきかはけっこう悩みます。
    私なりの結論としてブートローダ(もしくはスタートアップ)で一括で設定してしまい OS では管理しない方が良いとい思っています。
    上でも述べているようにシステム毎にポートの割り当てが変るので OS では管理できません。
    マクロとかで切り替えても良いかもしれませんが、コードが汚くなるだけでだれも嬉しくないと思います。

    あと、 UART を二つ使うとか良くあると思うのですが、そんな場合はどうするのですか?

    返信削除
  2. TOPPERSを使う時、私はいつもどこに何を入れるべきか凄く悩んでしまうのが実状です。
    色々ときめ細かく定義されているように見える半面、色んな場合にハマらない事があって悩んでしまう。バスの初期化とかドライバ周りなんてそんな感じです。

    確かにI/Oはブート時点で決めたいですよね。
    電気的にもその方が嬉しいです。

    TOPPERSを使って最初に疑問に思ったのはまさに複数UARTの件でした。
    「え?どうさせたいの?」って思うんです。

    開発者としてはできるだけ普通の表現にしたいわけですが、「どうさせたいのか?」が見えないので宙ぶらりんになってしまう。

    皆さんそうなんでしょうか?
    是非聞いてみたいです。

    返信削除