今回はPIC32MX250F128BをターゲットにMPLAB X v5.45+Harmony3を使用してSPI通信を行いました。その際にポイントとなる設定について紹介します。SPI接続のSRAM(IS62WVS5128FB)の書き込み、読み込みを行いました。なお、ターゲットへの書き込みはPickit3を使用しまし、MPLAB Xには予め、MPLAB Harmony 3 Launcher(旧名称 MPLAB Harmony Configurator 3)をインストールしています。
@プロジェクトファイル作成
MPLAB XのFile→New ProjectからMPLAB Harmony 3のプロジェクトを作成します。
AHarmony 3設定
Tools→Embedded→Harmony Configurator 3を選択します。左下のAvailable ComponentsからSPI1をクリックし、SPI1を追加します。SPI1が追加されると左上(Active Components)及び中央(Project Graph)にSPI1が表示されます。
中央(Project Graph)のSPI1をクリックし、右のConfiguration Optionsの設定項目を必要に応じて変更します。通常はデフォルトで問題ありません。SPIのデフォルトクロック周波数が低いため、1MHz程度に変更します。
また、今回はデバッグ用途にprintfを使用してuartからデバッグ情報を出力するため、UART2とSTDIOを追加しています。必要に応じてUART2のボーレートを右のConfiguration Optionsから変更してください。
Bピンアサイン設定
MHC→Tools→Pin Configurationを選択します。Pin DiagramからSPI1のSDO1、SDI1、SCK1を割り付けします。また、Pin SettingsからCSとしてRA0をGPIO設定しました。Pin TableからRA0を出力に設定し、通信を安定させるためにプルアップを有効にしました。
Cコード生成
設定完了後にGenerate Codeでコードを生成します。
DSPI通信関数
SPI通信をするためのコードを追加します。
SPI通信関数はSource Files/config/default/peripheral/spi/spi_master内のplib_spi1_master.cで定義されています。SPI初期化関数は既にinitialization.cに追加されているため、接続するデバイスに応じてSPI読み書き関数を追加します。SPI読み書きを同時にする場合はSPI1_WriteRead関数、読み込みのみの場合はSPI1_Read、書き込みのみの場合はSPI1_Writeの関数を使用します。なお、SPI1のConfiguration Options、Enable Interrupts設定はデフォルトで有効となっています。そのため、書き込み、読み込みした後はSPI1_IsBusy関数でSPI処理の完了を確認するか、SPI処理後に呼び出す関数をSPI1_CallbackRegisterで事前に登録する必要があります。SPI1_CallbackRegisterのサンプルはこちらに上がっているため、詳細の説明は省略します。今回はSPI1_IsBusy関数でSPI処理の完了を確認しました。
また、SPI通信で必要なCSは自動に設定(通信するときのみCSが自動でLOWになる)できますが、今回は手動でIO操作にしました。ピンアサイン設定でRA0を出力に設定したため、自動でHeader Files/config/default/peripheral/gpio内のplib_gpio.hにGPIO_RA0_Set関数やGPIO_RA0_Clear関数が追加されます。追加されたGPIO関数でCSを操作します。SRAMと通信するための全体のコードは下記です。main.cに下記のコードを追加しました。
#define SRAM_WRITE_CMD 2
#define SRAM_READ_CMD 3
void SramWrite(unsigned char *data, unsigned short length)
{
unsigned char wcmd[4];
wcmd[0]=SRAM_WRITE_CMD;
wcmd[1]=0;//High Addr
wcmd[2]=0;//Mid Addr
wcmd[3]=0;//Low Addr
GPIO_RA0_Clear();
SPI1_Write(wcmd,4);
while(SPI1_IsBusy()==true);
SPI1_Write(data,length);
while(SPI1_IsBusy()==true);
GPIO_RA0_Set();
}
{
unsigned char wcmd[4];
wcmd[0]=SRAM_WRITE_CMD;
wcmd[1]=0;//High Addr
wcmd[2]=0;//Mid Addr
wcmd[3]=0;//Low Addr
GPIO_RA0_Clear();
SPI1_Write(wcmd,4);
while(SPI1_IsBusy()==true);
SPI1_Write(data,length);
while(SPI1_IsBusy()==true);
GPIO_RA0_Set();
}
void SramRead(unsigned char *data, unsigned short length)
{
unsigned char wcmd[4];
wcmd[0]=SRAM_READ_CMD;
wcmd[1]=0;//High Addr
wcmd[2]=0;//Mid Addr
wcmd[3]=0;//Low Addr
GPIO_RA0_Clear();
SPI1_Write(wcmd,4);
while(SPI1_IsBusy()==true);
SPI1_Read(data,length);
while(SPI1_IsBusy()==true);
GPIO_RA0_Set();
}
{
unsigned char wcmd[4];
wcmd[0]=SRAM_READ_CMD;
wcmd[1]=0;//High Addr
wcmd[2]=0;//Mid Addr
wcmd[3]=0;//Low Addr
GPIO_RA0_Clear();
SPI1_Write(wcmd,4);
while(SPI1_IsBusy()==true);
SPI1_Read(data,length);
while(SPI1_IsBusy()==true);
GPIO_RA0_Set();
}
SPI1CONCLRやSPI1CONSET、LATACLR等のレジスタを操作してSPI通信やIO操作を行っていましたが、Harmony3でハードレイヤーが抽象化され、コード自動生成時点で最低限の関数が既に実装されています。設定によってはコード自動生成直後にも関わらず、ビルドエラーが発生してコードの修正が必要な場合がありますが、以前に比べると大分、改善しているように感じました。なお、SDカードといったHarmony3の機能や設定によってはSPI1_ReadやSPI1_Writeといった関数名が変わるため、注意が必要です。