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

自社標準仕様の製作
平成27年12月 27日

 汎用の高速シリアル通信機能(29)  SPIプログラムの注意点

 SPIプログラムについてある程度の動作検証が進んだので備忘録として幾つかの注意点を書いておきます。

 1.SPI送受信の開始
 SPIの送受信開始はマスタ送信側DMAによって行われます。より正確にはDMA機能に指定された割り込み信号によってDMAが起動されます。
この割り込み信号は割り込み許可フラグIECxの影響を受けません。SPIの場合は送信終了を示すSPIx Transmnsfer Done割り込みを使用します。
では、一番最初の送信開始はどうなるか?関連するレジスタのどれをセットした段階で動作を開始するのだろうか?

 最初はDMA機能にあるCFORCEビットとセットするものだと理解したのですが、これは誤りでした。
正しいのは「送信側DMA機能をONした段階からDMA転送が起動する」です。
    //DMAによるSPI転送の開始
    DCHxECONbits.CFORCE = 1;   // これは誤りでやってはいけない
    DCHxCONbits.ON = 1;        // 正解はこれで、DMAが起動開始と同時に転送が始まる

PIC32の割り込み信号には、その割り込みを要求した原因が取り除かれない限り割り込み信号をクリアできないものと、そうでないものがあります。
英語版のデータシートのInterrupt Controller項にある表にINTERRUPT IRQ. VECTOR AND BIT LOCATIONというのがあり、この表の右端にPersistent Interruptという項目があります。
この項目でYesとなっているのが、割り込み要因がクリアされない限り割り込み信号をクリアできない割り込みであることを示しています。

 このような割り込みでは、DMAが起動した段階で既に転送要求があるため、すぐにDMA転送が開始されます。
DMAを開始した後でDMAを強制開始させるCFORCEビットに'1'を書き込むと、本来とは別に余計なDMA転送が追加されるため一見理解不可能な動作を起こします。

 2.DMAの使用とFIFO
SPIやUARTといった周辺デバイスには数段のFIFOが実装されています。DMA転送を使用するならFIFOは必要ないとも考えられますが、今回は転送速度が従来とは桁違いに速い設定で使用します。他のプログラムからの影響を受けにくくする意味からもFIFOを有効にしておいた方が良いでしょう。
データシートを一通り読んだ限りでは、DMAとFIFOを同時に使用するなとは書いていないようです。嫌がらせに近い話ですが、プログラムで数十kBのデータ転送をDMAで行った場合には、このDMA chよりも優先度の低いDMA chを使った周辺デバイス側のDMA転送ではバッファオーバーフローを起こすことがあり得ます。

 3.C/C++コンパイラ出力の混在禁止
 これはSPIとは関係なく、XC32コンパイラの注意です。
 XC32 C/C++コンパイラでCコンパイラ(gcc)が出力したオブジェクトとC++コンパイラ(g++)が出力したオブジェクトを混在させるのは避けた方が良いようです。ある意味で当然といえば当然なんですが、結果的についやってしまう状況があり得るので注意が必要です。
 従来Cコンパイラで使用していた自作ライブラリをC++に移行するとき、従来のCプログラム部分をC++部分とは別のライブラリにすると、上記のような状況が発生します。ソースコードの拡張子は全て"c"になるのでMPLABはこのプロジェクトをCプログラムとしてgccでコンパイルします。
これを避けるためには、ダミーのソースファイルとして例えばdummy.cppをプロジェクトに追加します。追加ファイルの中身はコメントだけでも十分です。拡張子"cpp"のファイルがプロジェクトに追加されることによってMPLABはこのプロジェクトのソースファイルを全てg++でコンパイルするよう動作します。

 この混在ではCコンパイラとC++コンパイラの微妙な仕様の違いやバグなどが出てくるようです。どちらなのかは分からないですが。
私のところで問題になったのは、__PIC32_FEATURE_SET__というコンパイラが定義するマクロの動作がCとC++のコンパイラで異なり、Cコンパイラの出力が混在するとリンクが通りませんでした。



目次へ  前へ  次へ