AN-1479: ADuCM4050 の SPI フロー制御モード
はじめに
シリアル・ペリフェラル・インターフェース(SPI)は業界標準の同期シリアル・リンクで、A/Dコンバータ(ADC)、D/Aコンバータ(DAC)、デジタル・ポテンショメータ、不揮発性メモリ(NVM)、センサー、マイクロコントローラ・ユニット(MCU)などの他のSPI互換デバイスへの全二重動作が可能です。これらのデバイスの中には、高速化、イベント通知、コマンド応答メカニズムの実現など、特定目的のための特別な機能を備えているものがあります。
ADuCM4050のSPI動作モードは強化されており、半二重動作とフロー制御オプションを柔軟に使用できます。これにより、SPIブロックは、ペリフェラルに固有のこれらの特性のほとんどをハードウェアで自動的に使用できます。このため、ユーザ・コードが簡略化され、電力量効率を改善できます。
このアプリケーション・ノートでは、ADuCM4050 MCUで使用可能なSPIフロー制御モードについて説明し、使用例をいくつか示します。
背景
フロー制御は、マスタとスレーブ間のデータ・フローの同期に必要です。ADuCM4050 MCUは、差別化機能であるフロー制御をSPIで提供します。読出しコマンド・モードでは、フロー制御を使用して複数のデータ・バイトを受信できます。
フロー制御では、SPIマスタとスレーブ間のデータ転送は、定期的なデータ読出しまたはオンデマンドのデータ読出しに関するアプリケーション条件に基づいて制御されます。
ADuCM4050のSPIマスタは、次のモードのフロー制御をサポートします。
- ピンベースのフロー制御、SPIスレーブで制御。
- MISOピンを使用。
- RDYピンを使用。
- タイマーベースのフロー制御、SPIマスタで制御。
フロー制御モードについては、次のセクションで詳細に説明します。SPIフロー制御レジスタ(SPI_FLOW_CTL)のモード・フィールドは、フロー制御モードを3つのモードのいずれかに構成します。SPI_FLOW_CTLレジスタを図1に示します。
フロー制御機構は、ADuCM4050がSPIマスタとして構成されている場合に限り使用できます。
ピンベースのフロー制御
専用のRDYピンの使用
一部のSPIスレーブには、SPIマスタ(この場合は、ADuCM4050)のSPI_RDYピンに接続する専用のRDYピンがあります。SPI_RDYピンは、各SPIインスタンスに専用のピン(汎用入出力(GPIO)の代替機能)です。
例えば、ON Semiconductor®のCAT64LC40シリアル・フラッシュは、専用のRDYピンを使用して、SPIマスタにデータが使用できるかどうかを信号で通知します。
スレーブが専用のRDYピンをサポートしていない場合、ADuCM4050のRDYピンはSPIスレーブの割込みピンに配線できます。スレーブは、RDYピンを使用して、アクイジションとデータ処理が完了したことを示します。マスタは、このピンのアクティブなレベルが表示されるまでSPIクロックを提供しません。
RDYピンがアサートされたときに読出しを実行するバイト数を構成できます。この構成を実行するには、SPIフロー制御レジスタ(SPI_FLOW_CTL)のRDBURSTSZフィールドを設定します。MISOでこのバイトのバーストを受信した後、SPIマスタは、次のRDYピンのアサーションを待機し、次のバイトのセットを受信します。このプロセスは、SPIカウント・レジスタ(SPI_CNT)のセットのすべてのバイトが受信されるまで繰り返されます。
読出しコマンド・モードを使用すると、最大16バイトを転送できます。この転送は、SPI読出し制御レジスタ(SPI_RD_CTL)のTXBYTESフィールドを使用して構成されます。フロー制御を使用した場合に1回のバーストで受信されたバイト数は、SPI読出し制御レジスタ(SPI_FLOW_CTL)のRDBURSTSZフィールドで設定されます。ただし、受信バイトの合計数に上限は課せられません。
MISOピンの使用
一部のSPIスレーブには専用のRDYピンがありませんが、MISOピンを再利用してMISOでデータを送信する準備が整ったことをSPIマスタに通知する手法をとっています。これは、AD7798などの一部のADCでは一般的です。
ADuCM4050 SPIマスタは、MISOラインのアクティブ・レベルの遷移まで待機し、これが検出されると、RDBURSTSZ + 1個のバイトの読出しを実行して、次のアクティブ・レベルがMISOで検出されるまで待機状態に戻ります。
MISO/RDYピンの極性は、SPI読出し制御レジスタのRDYPOLフィールド(SPI_FLOW_CTL)を使用して構成できます。
タイマーベースのフロー制御
専用ピンがないスレーブから、マスタにデータが使用できるかどうかを通知するには、MCUで16ビット・タイマーを使用してデータの読出し中に待機状態を導入します。タイマーがトリガすると、マスタはバイトのバースト(RDBURSTSZ + 1)の読出しを実行し、タイマーを再起動します。タイマーはSPIクロック・レート(SCK)で出力され、タイマーのトリガを待機するSCKサイクルの数は、SPI_WAIT_TMRレジスタを使用して設定できます。例については、図2を参照してください。
このスキームを、フロー制御でSCKの待機と駆動に使用する場合は、最後のSCKエッジをサンプリング・エッジにする必要があります。待ち時間が終わったら、SCK駆動エッジが次のデータ転送を実行します。
ソース・コード
このセクションでは、ハードウェア・フロー制御モードを使用して、フロー制御機能によりユーザ・コードとシステム内の電力節約を簡素化する方法を説明します。
このセクションでは2つの例を示します。1つはタイマーベースの概念を示し、もう1つはピンベースの例を示します。
タイマーベースのフロー制御の例
SPIフロー・オプションを介してデバイスを自動的に制御する第1の方法はタイマーです。タイマーベースのフロー制御のセクションで説明したように、SPIブロックは連続する転送間に設定可能な遅延を追加します。この方法は、固定周波数のサンプリング・レートとデータ・レートでデータ・ストリームを提供するようなADCやセンサーでは一般的です。
SPIフローの方法はSPI_FLOW_CTLレジスタで示されます。この場合、SPI_FLOW_CTL.MODEでタイマー・オプションは1に設定します。
遅延は、PCLK周波数とSPI_WAIT_TMRレジスタに依存します。このレジスタの値は、新しいSPI動作の実行を待機するSPI_CLKサイクル数(PCLK/SPI_DIV)を指定します。
この他に考慮すべきオプションは次のとおりです。
- SPI_CTL.CONTINUOUSビット・フィールド:すべてのデータが転送されるまで転送シーケンスを継続する。
- SPI_CNTレジスタ:転送するバイト数。
- SPI_FLOW_CTL.RDBURSTSZビット・フィールド:転送ごとに読出しバイト数から1を引いた数。
これらのフィールドの効果を図5に示します。
この例では、プログラムは固定数のワードを読み出し、タスクが完了するとプログラムが終了します。コードは、コード例1のセクションに示しています。
受信データは割込みハンドラで読み出されます。この場合、読出しバッファが一杯になり、values変数が増加されます(コード例2を参照)。
結果を図3と図4に示します。これらの図は、あるバーストと次のバーストの間の遅延を制御するWAIT_TMRレジスタ値を変更することによって作成されています。
コード例1
#define NUM_VALUES 50 volatile uint16_t values = 0; uint16_t buffer[NUM_VALUES] = {0}; […] NVIC_EnableIRQ(SPI0_EVT_IRQn);
pADI_SPI0->CS_OVERRIDE = 0; pADI_SPI0->CTL = (1 << BITP_SPI_CTL_CON) | //連続 (1 << BITP_SPI_CTL_CPOL) | //極性 (1 << BITP_SPI_CTL_CPHA) | //フェーズ (1 << BITP_SPI_CTL_MASEN) | //マスタ (1 << BITP_SPI_CTL_SPIEN); //イネーブル pADI_SPI0->IEN = (1 << BITP_SPI_IEN_IRQMODE); //2バイトごとにtx割込み pADI_SPI0->CNT = NUM_VALUES * 2; //転送バイト数(サンプルあたり2バイト) pADI_SPI0->RD_CTL = (0 << BITP_SPI_RD_CTL_TXBYTES) | //読出しコマンドでは、tx -1 (1 << BITP_SPI_RD_CTL_CMDEN); //コマンド・モード pADI_SPI0->FLOW_CTL = (1 << BITP_SPI_FLOW_CTL_RDBURSTSZ) | //バースト -1 (1 << BITP_SPI_FLOW_CTL_MODE); //WAIT_TMRベースのフロー制御 pADI_SPI0->WAIT_TMR = 20; //待機するサイクル数
tmp = pADI_SPI0->RX; //転送を開始するためのダミー読出し
while(values < NUM_VALUES); //すべてのサンプルまで待機
コード例2
void SPI0_Int_Handler(){ uint16_t aux = 0;
if((pADI_SPI0->STAT & 0x20) == 0x20){ //TX終了 pADI_SPI0->STAT = 0x22; }else if((pADI_SPI0->STAT & 0x40) == 0x40){ //RX
pADI_SPI0->STAT = 0xFFFF; // 割込みをクリア
aux = (pADI_SPI0->RX << 8); aux |= pADI_SPI0->RX;
buffer[values++] = aux; } }
ピンベースのフロー制御の例
SPIフローの第2の方法は、新しい転送を信号で通知する方法ですこの例では、MISOラインがレディ信号として使用されています。
この例では、AD7798 ADCへのインターフェースを実装しています。このADCは、サンプルを自動的に送信する自律モードで動作するように設定できます。新しいサンプルが準備できると、MISOラインにより通知されます。連続モードを選択する設定は、0x5Cの値を書き込むことで行います。これは、連続モードで次に読み出す対象がデータ・レジスタであることをCOMレジスタで示します。
連続モードは、AD7798からサンプルを連続的に読み出す手段です。各サンプルは16ビット・ワードで、ADCによってMISOラインがグラウンドに接続された後でのみ使用できます。ワークフローを図7に示します。
SPI_FLOW_CTL.CTL_MODEビット・フィールドに3を書き込むことにより、SPIフロー・オプションとしてADuCM4050のSPIをMISOモードに設定する必要があります。この方法でも、同じレジスタ内のRDYPOLビット・フィールドが考慮されます。この場合、ローの値がトリガとなるため、1を書き込む必要があります。
各転送は16ビット幅ワードであるため、SPI_CTL.IRQMODEに1の値を設定する必要があります。これは、RXバッファに2バイトが入ったときに割込みを通知するのに使用されます。更に、SPI_FLOW_CTL.RDBUSTSZが1になることは、転送ごとに16ビットクロック・サイクルが完了したことを示します。
最後に、デバイスを正しく設定するために、AD7798に設定ワード(0x5C)を書き込む必要があります。
コードは、コード例3のセクションに示しています。
読出しは、割込みハンドラの関数でも実行できます(コード例4のセクションを参照)。
この結果、図6に示すようなデータ・ストリームになります。AD7798 ADCは新しいサンプルが使用できることを通知し、このデータをMISOラインに出力します。各読出しで、ADuCM4050はクロック(青色)を生成し、転送全体が終了するまでチップ・セレクト・ラインをローに保ちます(ピンク色)。MOSIラインは初期設定後は必要ありません(緑色)。
コード例3
NVIC_EnableIRQ(SPI0_EVT_IRQn);
pADI_SPI0->CS_OVERRIDE = 0; pADI_SPI0->CTL = (1 << BITP_SPI_CTL_CON) | //連続 (1 << BITP_SPI_CTL_CPOL) | //極性 (1 << BITP_SPI_CTL_CPHA) | //フェーズ (1 << BITP_SPI_CTL_MASEN) | //マスタ (1 << BITP_SPI_CTL_SPIEN); //イネーブル pADI_SPI0->IEN = (1 << BITP_SPI_IEN_IRQMODE); //2バイトごとにtx割込み pADI_SPI0->CNT = NUM_VALUES * 2; //転送バイト数 pADI_SPI0->RD_CTL = (0 << BITP_SPI_RD_CTL_TXBYTES) | //読出しコマンドではtx -1 (1 << BITP_SPI_RD_CTL_CMDEN); //コマンド・モード pADI_SPI0->FLOW_CTL = (1 << BITP_SPI_FLOW_CTL_RDBURSTSZ) | //バースト -1 (1 << BITP_SPI_FLOW_CTL_RDYPOL) | //レディ信号の極性:ロー (3 << BITP_SPI_FLOW_CTL_MODE); //MISOベースのフロー制御
pADI_SPI0->TX = 0x5C; //AD7798を連続モードに設定 tmp = pADI_SPI0->RX; //転送を開始するためのダミー読出し
while(values < NUM_VALUES);
コード例4
void SPI0_Int_Handler(){ uint16_t aux = 0;
if((pADI_SPI0->STAT & 0x20) == 0x20){ //TX 終了 pADI_SPI0->STAT = 0x22; }else if((pADI_SPI0->STAT & 0x40) == 0x40){ //RX
pADI_SPI0->STAT = 0xFFFF; // 割込みをクリア
aux = (pADI_SPI0->RX << 8); aux |= pADI_SPI0->RX;
buffer[values++] = aux; } }
まとめ
読出しコマンド・モードやフロー制御などのADuCM4050 SPIの種々の機能により、このデバイスは、SPIペリフェラルでMCUの負担を軽減するバッテリ駆動システムに最適で、データ収集に個別に使用できます。
これらの特性をハードウェアで実装することで、遅延やライン操作などの一部の動作が設定不要になるため、ユーザ・コードを簡略化できます。また、MCUが不要になるため、ADuCM4050の特性により電力量消費を高効率化できます。
ADuCM4050の特性を、ダイレクト・メモリ・アクセス(DMA)およびフレキシ・モードと組み合わせて実装することにより、電力量効率と生産性を大幅に向上させることができます。