スパイス  組み込み制御装置の受注製作

ライブラリの導入
平成27年 4月27日

 PIC32の周辺機能(USART)を活用する(その4) 通信仕様の検討
 USARTの初期化と割り込み処理の記述が出来ました。次は通信の仕様について検討していきます。
    訂正:
 基本的な認識誤りをしていました。PIC32のUSARTでは、受信時の割り込みタイミングの選択でFIFOが8バイトフルになる選択は出来ません。少し分かり難いのですが、PIC24では4バイトFIFOがフルになる選択が出来たのに対して、PIC32ではこの選択肢は予約済みとなっています。最大でFIFOバッファの3/4が一杯になった段階で割り込みを起動できます。今回の方式では時間を制御のパラメートとして使っているので、どうしても割り込みが必要です。過去の記述は少しずつ訂正していきます。
 また、昨日書いたUSARTの初期化関数ですが、どうも問題があるようです。正しく動くプログラムと不安定な動作となるプログラムが出てきました。詳しい原因は特定できないのですが、どうも省電力機能の関係でMODEレジスタとSTAレジスタの設定に順番があるようです。とりあえず現時点で問題なく動作したものに変更してあります。


 基本的なアイデアは既に説明しました。通信データをPIC32のUSARTが持つFIFOの段数だけブロックとしてまとめて転送します。受信側も同じ数だけ受信を完了した段階で受信割り込みを起動します。
この方式のメリットは、1ブロックの転送が終了するまでの転送速度は事実上CPUの動作速度とは無関係に高くすることが出来る点です。1ブロックの転送終了後は、受信側CPUが受信データを正しく取り込むのに十分な時間を空ける必要があります。

 後は、この方式にもう少し具体的な制約を追加して、途中で不測の通信エラーが起きても再実行することで正しい通信を継続できるように仕様を決めていきます。
 基本となる前提は下記です。

 他の通信方式を参考に、上記の前提で仕様を決めていきます。
通信データの最大値を255バイトとすると、一回の転送で送受信できる6バイトのデータを数十回に分けて転送することになります。転送データの書式は幾つかの方式があるようですが、今回は最もデータ量が少なくなる方式を採用します。  つまり、アドレス01番地に転送するデータが0,1,2,3,4,5,6,7,8,9,a,b,c,d,e,f(アスキー文字ではなく数字です)の16個であった場合、
最初の伝送データ(6バイト)は '1', '18', '0', '1', '2', '3'
二回目の伝送データ(6バイト)は '4', '5', '6', '7', '8', '9'
三回目の伝送データ(6バイト)は 'a', 'b', 'c', 'd' , 'e', 'f'
最後の伝送データ(6バイト)は '<CRC1>', '<CRC2>', '0', '0', '0', '0'
となります。なお、転送データが6バイトに満たないブロックでは末尾に'0'を追加すると仮定しています。

 このように決めると、転送できる最大文字数は255文字から先頭の2バイトとCRC2バイトを除く251バイトになります。
これだけあれば実用上不満は少ないでしょう。

 このように決めると、転送途中で通信エラーが起きた場合でも、次の先頭データを確実に検出さえ出来れば、その後の通信は問題なく継続できます。特にスレーブ側では、マスタから送られた先頭データの検出が必須です。
以上の検討から下記のようなタイミングを規定します。

 はず始めに、最初のデータ転送前後のタイミング図を示します。図中のDnやRnはマスタ側から見て各6バイトの送信データと受信データを示しています。
マスタ側    [Dn]|<------ T1 ---------->[D1]<---- T2 ---->[D2]<--   -->[Dn]|<----- T5 ------->    
         --------------------------------------------------------------------------------------------------
スレーブ側  [Dn]|                                                         |<-T3->|  [R1]<-- T4 -->[R2]

 通信の仕様からマスタが最初に送信するデータを全てのスレーブは確実に認識できる必要があります。これはマスタからの二番目以降の送信データとも区別できることを意味しています。その後、他のスレーブが応答データを返しても、これをマスタから自分への先頭データと誤認しないなら問題ありません。単に無視すれば済みます。

 この最初の送信[D1]を他の送受信と区別するために、マスタの最初の送信開始前に空白時間T1を確保します。この時間T1は後から説明するT2よりも長い時間に設定することになります。スレーブでは送受信の度に時刻を記録し、前回の送受信からの経過時間によって最初の送信データであるかどうかを判断します。ここでいう[送受信の度」とは6バイトを一塊とする送信・受信を行ったことを示します。

 次にはマスタからの二番目以降のデータ送信です。図では[D2], [Dn]が該当します。ここもスレーブが受信データを確実に処理できるだけの待ち時間T2を確保します。T2はT1と区別できるだけの時間的な差が必要です。一つの目安としてT1の値はT2の2倍程度に設定しておきます。
 マスタからの送信が終了後、マスタは通信ポートを送信から受信に切り替える必要があります。この切り替えまでの時間を確保するためにT3が規定されます。スレーブは受信データを処理して応答を返すとき少なくともT3時間が経過するまで応答を返すことは許されません。
 応答データの送信間隔を規定しているのがT4です。これはマスタ側の割り込み処理能力に対して十分な余裕を持った値に設定します。
 最後はマスタからの送信が正しくスレーブに届かなかった場合を想定して、スレーブから全く応答がないときのタイムアウト時間T5を決めておきます。


 以上の時間を規定すれば、通信は問題なく動作する筈ですが、実はまだ不十分です。
通常のように1バイト単位でCPUが送受信を行うならこれで十分ですが、今回は6バイト単位での送受信を行います。送信側は6バイトを送信したものの受信側では受信エラーによって6バイト単位の同期がズレてしまう可能性が考えられます。
しかし、実際にそんなことが起きるのか?これに結論を出すにはFIFOの機能と仕様について詳細な検討が必要です。
まず、最初に6バイトの受信データのどこかでエラーが発生した場合、スレーブはどのようにエラーを検出するかをタイミング図に描いてみます。
マスタ側    [B1][B2][B3][B4][B5][B6]|
         --------------------------------------------------------------------------------------------------
スレーブ側            |(エラー発生) |[割り込み処理]
 上の図で各Bnは1バイトの送信を示しています。このとき3バイト目の送信データでエラーが起きたとします。スレーブがこのエラーを検出できるのは、エラー発生直後でしょうか?それともそれ以外のタイミングでしょうか?
「スレーブがこのエラーを検出できる」とは、受信エラー割り込みが発生するタイミングはどこかという疑問です。エラーデータ受信直後かFIFOからCPUが読み出す直前かのどちらかでしょうが、データシートの記述からは非常に微妙です。エラービットまでFIFOされているかどうかという説明の方が分かりやすいかもしれません。
 実際に動かして確認してみます。

 仮に、すぐに受信エラー割り込みが発生するなら、この段階でFIFOのデータを全て読み出す必要があるのでマスタとの6バイト単位の同期は崩れます。逆に6バイト受信後CPUが読み出す直前までエラー割り込みが発生しないとしても、6バイト単位の先頭バイトで受信エラーが発生すればその段階で受信エラー割り込みが発生すると考えられます。やはり同期が崩れることになります。
 いずれにしてもスレーブから応答がない状況では、マスタとスレーブ間の再同期処理を考える必要があります。これについては、エラーの発生タイミングを実験で確認した後で検討します。


目次へ  前へ  次へ