RSPIは名前の通りSPI専用の機能であり設定可能な項目が多いです。でも1チャネルしかないです。
SCIはハードウェアマニュアルにも簡易SPI機能とあるように設定が少ないです。でも5チャネルあります。
SCIでも機能は十分だと思うので、状況に合わせて好きな方を使えば良いと思います。 今回は都合で両方使ってみたので両方の機能をマスターモードで動作させたときの非常にシンプルな使用例をメモします。
条件
- 動作:マスターマイコンとスレーブマイコン間で1バイトのSPI通信の送信・受信
- マスターマイコン:R5F52206BDFM(秋月で売ってるやつ)
- スレーブマイコン:atmega328P-PU(秋月で売ってるやつ)
- 開発環境:e2studio/Renesas Flash Programmer
回路
それぞれのSPI通信ピンに接続しただけです。RX220は秋月のマイコンボード使用しているのでチップのピン番号ではありません。
今回一対一想定のためスレーブのSSピンはGNDに落としてます。
使用例
ありがたいことにハードウェアマニュアルに初期化、送信、受信のフロー例が全て記載されているため、それに従って記載するだけです。だけのはず。
結構前に書いたコードのため色々試行錯誤した記憶がありますが、詳細を忘れました。見返すとフローの理解を間違えてるっぽくてこれアカンのでは?という気がしますが、これでも一応動くよってことで残しておきます。
まずは初期化。
マスターモードの初期化フロー図と作成した関数がこちら。
・初期化関数
続きまして送信処理です。
・送信関数
・送信関連割込関数(intprg.cより)
本来SPDRはフロー図に記載してある通りSPTI割り込み処理でライトすべきなのでしょうが、特に気にせず送信関数内でライトしてますね。 おそらくSPTI割り込み処理は何にも役立ってないでしょう。そして、SPII割り込みとSPRI割り込みを待っていますが、おそらくSPRI必要無いと思われます。
一応このコードで動いていますが、以上の問題点は気が向いたら修正したいところ。
そして初期化関数→送信関数実施時の出力波形図はこちら。
黄色がSCK、青色がMOSIです。送信値は0x01。
続きまして、受信処理です。
RSPI
結構前に書いたコードのため色々試行錯誤した記憶がありますが、詳細を忘れました。見返すとフローの理解を間違えてるっぽくてこれアカンのでは?という気がしますが、これでも一応動くよってことで残しておきます。
まずは初期化。
マスターモードの初期化フロー図と作成した関数がこちら。
・初期化関数
/* RSPI initialize */
void rspi_init( void )
{
//RSPI機能有効化
SYSTEM.PRCR.WORD = 0xA50B; // clock source protect release
MSTP( RSPI0 ) = 0; // RSPI0 Enable
SYSTEM.PRCR.WORD = 0xA500; // clock source protect
//SPPCR触らない/SPBRはSPCMDと同時に設定
// SSLPをなぜここで
RSPI0.SSLP.BIT.SSL0P = 0; // SSLA0 active low
//SPDCRの設定
RSPI0.SPDCR.BIT.SPFC = 0; // 1 frame
RSPI0.SPDCR.BIT.SPRDTD = 0; //receive buffer
RSPI0.SPDCR.BIT.SPLW = 1; //long access
//SPND触らない
//SPCR2設定
RSPI0.SPCR2.BYTE = 0; // parity none, idle irpt none
//SPCMD設定
RSPI0.SPCMD0.BIT.LSBF = 0; // MSB first, data length:8bit
RSPI0.SPCMD0.BIT.CPHA = 0; // phase setting
RSPI0.SPCMD0.BIT.BRDV=0; // SPI clock 200kHz
RSPI0.SPBR=79;
//割込コントローラ設定
IEN( RSPI0, SPRI0 )=1; // interrupt enable
IPR( RSPI0, SPRI0 )=15; // interrupt priority min
IEN( RSPI0, SPTI0 )=1;
IPR( RSPI0, SPTI0 )=15;
IEN( RSPI0, SPII0 )=1;
IPR( RSPI0, SPII0 )=15;
//DMAC未使用
//入出力ポートの設定
PORTC.PDR.BIT.B5 = 1; // out(SCK)
PORTC.PDR.BIT.B6 = 1; // out(MOSI)
PORT1.PDR.BIT.B7 = 0; // in(MISO)
MPC.PWPR.BIT.B0WI = 0; // PFSWE write release
MPC.PWPR.BIT.PFSWE = 1; // PFS write release
MPC.PC5PFS.BIT.PSEL = 13; // PC5 function RSPCKA
MPC.PC6PFS.BIT.PSEL = 13; // PC6 function MOSIA
MPC.P17PFS.BIT.PSEL = 13; // P17 function MISOA
MPC.PWPR.BIT.PFSWE = 0; // PFS write protect
MPC.PWPR.BIT.B0WI = 1; // PFSWE write protect
PORTC.PMR.BIT.B5 = 1; // PC5 peripheral mode
PORTC.PMR.BIT.B6 = 1; // PC6 peripheral mode
PORT1.PMR.BIT.B7 = 1; // P17 peripheral mode
//SPCR設定
RSPI0.SPCR.BIT.SPMS = 0; // SPI mode
RSPI0.SPCR.BIT.MSTR = 1; // master mode
// error flag clear
RSPI0.SPSR.BIT.OVRF = 0; //over run error flag
RSPI0.SPSR.BIT.MODF = 0; //mode fault error flag
RSPI0.SPSR.BIT.PERF = 0; //parity error flag
// interrupt flag disable
RSPI0.SPCR2.BIT.SPIIE = 0; //SPII interrupt disable
RSPI0.SPCR.BIT.SPTIE = 0; // send interrupt disable
RSPI0.SPCR.BIT.SPRIE = 0; // receive interrupt disable
RSPI0.SPCR.BIT.SPEIE = 0; // error interrupt disable
RSPI0.SPCR.BIT.SPE = 0; // RSPI disable
//SPCRリード
RSPI0.SPCR.BYTE; // empty read
}
初期状態で設定いじりそうにない設定は触ってません。また、頭にはRXマイコン使用時には気を付けなければいけない機能有効化を入れています。
この初期化関数実行後、送信/受信関数を実行すれば通信可能な形にしています。割り込みコントローラで有効にしている割り込みは送信/受信フローに出てきます。
続きまして送信処理です。
・送信関数
/* RSPI send */
void rspi_send( unsigned char send_data )
{
//エラー要因のクリア
RSPI0.SPSR.BIT.OVRF = 0; //over run error flag
RSPI0.SPSR.BIT.MODF = 0; //mode fault error flag
RSPI0.SPSR.BIT.PERF = 0; //parity error flag
//SPII割込みを禁止
RSPI0.SPCR2.BIT.SPIIE = 0; //SPII interrupt disable
//SPEビットの許可 同時に必要な割り込みを許可
RSPI0.SPCR.BIT.SPE = 1; // RSPI enable
RSPI0.SPCR.BIT.SPRIE = 1; //receive interrupt enable
//SPDRへ送信データをライト
RSPI0.SPDR.LONG = send_data; // send data write
//1バイトなので最終データをライトしたとしてフラグセット
RSPI0.SPCR2.BIT.SPIIE = 1; //SPII interrupt enable
//SPII割り込み発生確認
while( RSPI0.SPCR2.BIT.SPIIE ); // flag clear wait
while( RSPI0.SPCR.BIT.SPRIE ); // flag clear wait
//必要あるか不明
send_data = RSPI0.SPDR.LONG; //empty read
//SPEビットの禁止
RSPI0.SPCR.BIT.SPE = 0; // RSPI disable
}
・送信関連割込関数(intprg.cより)
/* send empty interrupt */
void Excep_RSPI0_SPTI0(void)
{
RSPI0.SPCR.BIT.SPTIE = 0; //SPTI interrupt clear
}
/* send finish interrupt */
void Excep_RSPI0_SPII0(void)
{
RSPI0.SPCR2.BIT.SPIIE = 0; //SPII interrupt clear
}
/* receive finish interrupt */
void Excep_RSPI0_SPRI0(void)
{
RSPI0.SPCR.BIT.SPRIE = 0; //SPRI interrupt clear
}
SPTIは送信バッファエンプティ割り込み、SPRIは受信バッファフル割り込み、SPIIは送信完了割り込みです。エラーが生じた際の割込みとしてSPEIも機能としてはありますが使用してません。本来SPDRはフロー図に記載してある通りSPTI割り込み処理でライトすべきなのでしょうが、特に気にせず送信関数内でライトしてますね。 おそらくSPTI割り込み処理は何にも役立ってないでしょう。そして、SPII割り込みとSPRI割り込みを待っていますが、おそらくSPRI必要無いと思われます。
一応このコードで動いていますが、以上の問題点は気が向いたら修正したいところ。
そして初期化関数→送信関数実施時の出力波形図はこちら。
黄色がSCK、青色がMOSIです。送信値は0x01。
続きまして、受信処理です。
・受信関数
/* RSPI receive */
void spi_recv( unsigned char* recv_data )
{
//エラー要因のクリア
RSPI0.SPSR.BIT.OVRF = 0; //over run error flag
RSPI0.SPSR.BIT.MODF = 0; //mode fault error flag
RSPI0.SPSR.BIT.PERF = 0; //parity error flag
//SPII割り込みを禁止
RSPI0.SPCR2.BIT.SPIIE = 0; //SPII interrupt disable
//SPEビットの許可 同時に必要な割り込みを許可
RSPI0.SPCR.BIT.SPE = 1; // RSPI enable
RSPI0.SPCR.BIT.SPRIE = 1; //receive interrupt enable
RSPI0.SPDR.LONG = 0xFF; // dummy data write
//SPII割り込みを許可し送信完了待機
RSPI0.SPCR2.BIT.SPIIE = 1; //SPII interrupt enable
while( RSPI0.SPCR2.BIT.SPIIE ); // flag clear wait
//SPRI割り込み待機
while( RSPI0.SPCR.BIT.SPRIE ); // flag clear wait
//SPDRから受信データ1byteをリード
*recv_data = (RSPI0.SPDR.LONG&0xFF); //receive data read
//1バイトなので最終データをリードしたとしてフラグクリア
RSPI0.SPCR.BIT.SPE = 0; // RSPI disable
}
・受信関連割込関数は送信と同様のため割愛
大分フローと異なるコードとなっておりますが、クロックをダミーデータの送信処理を行うことで発生させ、そのときの受信値によってSPRI割り込みを発生させていますね。
送信処理をせずともこのフロー図通りに受信できるんですかねこれ。
また、SPDRのリードは本来SPRI割り込み処理内で行うべきなのでしょうが、受信関数内で実施しています。
一応このコードで動いていますが、以上の問題点は送信処理同様いつか確認したいですね。
そして初期化関数→受信関数実施時の出力波形図はこちら。
黄色がSCK、青色がMOSIですね。送信値は0x02です。
RSPIの使用例は以上、次はSCIによるSPI通信例です。
同じくまず初期化。
・初期化関数
続きまして送信処理。
・送信関数
こちらは図に記載があるようにTDRへの書き込みをTXI割り込みで実施しています。 そのためにグローバル変数のsend_bufを使用してます。
ただ、TXI割り込み処理中にTIEビットを0にしているのにも関わらず二回TXI割り込みが入ってしまう現象がありましたので、TIEビットが0になっていたら処理せず終了させるという場当たり的な書き方をしています。原因がわかったら修正します。
そして初期化関数→送信関数実施時の出力波形図はこちら。
黄色がSCK、青色がMOSIです。送信値は0x04です。
おかしいところとして意図せずクロック送信前にMOSIが一度HIGHになってます。原因はよくわかりません。この立ち上がりはクロック位相セレクトビット(SPMR.CKPH)で遅れなしにすると1クロック目に重なるので、遅れありにしてずらすことで無視しています。どこか設定すれば直るんですかね。
続きまして受信処理。
・受信関数
こちらも図に記載があるようにRDRの読み込みをRXI割り込みで実施しています。 そのためにグローバル変数のrecv_bufを使用してます。
あとはフロー図通りになるように書いたつもりです。
そして初期化関数→受信関数実施時の出力波形図はこちら。
黄色がSCK、青色がMOSIです。受信値は0x04です。
動作的に問題はありませんが、最後のクロックの立ち下がりの早さよ。
以上RSPIとSCIのマスターモードでの使用例でした。スレーブモードは使う機会があれば。
また今回スレーブとして使用したatmega328PのSPI通信も簡単に記載したいと思います。ただマニュアルにコード例まで記載してあるので、あえて残す意味があるのかといわれるとおそらく無い。
大分フローと異なるコードとなっておりますが、クロックをダミーデータの送信処理を行うことで発生させ、そのときの受信値によってSPRI割り込みを発生させていますね。
送信処理をせずともこのフロー図通りに受信できるんですかねこれ。
また、SPDRのリードは本来SPRI割り込み処理内で行うべきなのでしょうが、受信関数内で実施しています。
一応このコードで動いていますが、以上の問題点は送信処理同様いつか確認したいですね。
そして初期化関数→受信関数実施時の出力波形図はこちら。
黄色がSCK、青色がMOSIですね。送信値は0x02です。
RSPIの使用例は以上、次はSCIによるSPI通信例です。
SCI
同じくまず初期化。
・初期化関数
/* SCI initialize */
void sspi_init(void)
{
//SCI機能有効化
SYSTEM.PRCR.WORD = 0xA50B; // clock source protect release
MSTP( SCI5 ) = 0; // SCI5 Enable
SYSTEM.PRCR.WORD = 0xA500; // clock source protect
//機能・割り込み禁止
SCI5.SCR.BIT.TIE = 0; //TXI interrupt disable
SCI5.SCR.BIT.RIE = 0; //RXI interrupt disable
SCI5.SCR.BIT.TE = 0; //send interrupt disable
SCI5.SCR.BIT.RE = 0; //receive interrupt disable
SCI5.SCR.BIT.TEIE = 0; //TEI interrupt disable
//割込コントローラ設定
IEN( SCI5, TXI5 )=1; // interrupt enable
IPR( SCI5, TXI5 )=15; // interrupt priority
IEN( SCI5, RXI5 )=1;
IPR( SCI5, RXI5 )=15;
IEN( SCI5, TEI5 )=1;
IPR( SCI5, TEI5 )=15;
//IOポート設定
PORTC.PDR.BIT.B2 = 0; //MISO
PORTC.PDR.BIT.B3 = 1; //MOSI
PORTC.PDR.BIT.B4 = 1; //SCK
MPC.PWPR.BIT.B0WI = 0; // PFSWE write release
MPC.PWPR.BIT.PFSWE = 1; // PFS write release
MPC.PC2PFS.BIT.PSEL = 10; // PC2 function RSPCKA
MPC.PC3PFS.BIT.PSEL = 10; // PC3 function MOSIA
MPC.PC4PFS.BIT.PSEL = 10; // PC4 function
MPC.PWPR.BIT.PFSWE = 0; // PFS write protect
MPC.PWPR.BIT.B0WI = 1; // PFSWE write protect
PORTC.PMR.BIT.B2 = 1; // PC2 peripheral mode
PORTC.PMR.BIT.B3 = 1; // PC3 peripheral mode
PORTC.PMR.BIT.B4 = 1; // PC4 peripheral mode
//CKEビットを設定
SCI5.SCR.BIT.CKE = 1; //clock:internal baud rate
//IICMを0に設定、CKPH、CKPOLビットを設定
SCI5.SIMR1.BIT.IICM = 0; // simple spi mode
SCI5.SPMR.BIT.SSE = 0; // SSpin disable
SCI5.SPMR.BIT.CKPOL = 0; //clock pole no change
SCI5.SPMR.BIT.CKPH = 1; //clock delay
//SMR、SCMRレジスタに送信/受信フォーマットを設定
SCI5.SMR.BIT.CKS = 3; //clock:PCLK/64
SCI5.SMR.BIT.CM = 1; // clock synchro
SCI5.SCMR.BIT.SMIF = 0; //SCImode
SCI5.SCMR.BIT.SINV = 0; //no invert
SCI5.SCMR.BIT.SDIR = 1; //MSB
//BRRレジスタに値を設定
SCI5.BRR = 1; //60 kHz
//SCR.TE、REビットの設定は送信/受信関数で使用する
}
基本的にはRSPIと同様です。こっちは大体図の通りに書いてます。
続きまして送信処理。
・送信関数
/* SCI send */
//global variable
unsigned char send_buf;
void sspi_send( unsigned char send_data )
{
send_buf = send_data;
SCI5.SCR.BIT.TIE = 1; //TXI interrupt enable
SCI5.SCR.BIT.TE = 1; //send interrupt enable
while( SCI5.SCR.BIT.TE ); // send finish wait
}
・送信関連割込関数(intprg.cより)
/* TXI interrupt */
void Excep_SCI5_TXI5(void)
{
if(SCI5.SCR.BIT.TIE == 0) return;
SCI5.TDR = send_buf; // send buffer write
SCI5.SCR.BIT.TIE = 0;
SCI5.SCR.BIT.TEIE = 1;
}
/* TEI interrupt */
void Excep_SCI5_TEI5(void)
{
// send end
SCI5.SCR.BIT.TE = 0;
SCI5.SCR.BIT.TIE = 0;
SCI5.SCR.BIT.TEIE = 0;
}
TXIは送信データエンプティ割り込み、TEIIは送信完了割り込みです。こちらもエラーが生じた際の割込みとしてERIが機能としてはありますが使用してません。こちらは図に記載があるようにTDRへの書き込みをTXI割り込みで実施しています。 そのためにグローバル変数のsend_bufを使用してます。
ただ、TXI割り込み処理中にTIEビットを0にしているのにも関わらず二回TXI割り込みが入ってしまう現象がありましたので、TIEビットが0になっていたら処理せず終了させるという場当たり的な書き方をしています。原因がわかったら修正します。
そして初期化関数→送信関数実施時の出力波形図はこちら。
黄色がSCK、青色がMOSIです。送信値は0x04です。
おかしいところとして意図せずクロック送信前にMOSIが一度HIGHになってます。原因はよくわかりません。この立ち上がりはクロック位相セレクトビット(SPMR.CKPH)で遅れなしにすると1クロック目に重なるので、遅れありにしてずらすことで無視しています。どこか設定すれば直るんですかね。
続きまして受信処理。
・受信関数
//* SCI receive */
//global variable
unsigned char recv_buf;
void sspi_recv( unsigned char* recv_data )
{
SCI5.SCR.BIT.RIE = 1; //RXI interrupt enable
SCI5.SCR.BIT.RE = 1; //receive interrupt enable
while( SCI5.SCR.BIT.RE ) // receive finish wait
{
if(SCI5.SSR.BIT.ORER)
{
SCI5.RDR; // delete error data
SCI5.SSR.BIT.ORER = 0; //overrun error flag clear
while( SCI5.SSR.BIT.ORER )SCI5.SSR.BIT.ORER = 0;
SCI5.SCR.BIT.RE = 0; //RXI interrupt disable
SCI5.SCR.BIT.RIE = 0; //receive interrupt disable
}
}
*recv_data = recv_buf;
}
・受信関連割込関数(intprg.cより)
/* RXI interrupt */
void Excep_SCI5_RXI5(void)
{
recv_buf = SCI5.RDR; // receive buffer read
// receive end
SCI5.SCR.BIT.RIE = 0;
SCI5.SCR.BIT.RE = 0;
}
RXIは受信データフル割り込みです。
こちらも図に記載があるようにRDRの読み込みをRXI割り込みで実施しています。 そのためにグローバル変数のrecv_bufを使用してます。
あとはフロー図通りになるように書いたつもりです。
そして初期化関数→受信関数実施時の出力波形図はこちら。
黄色がSCK、青色がMOSIです。受信値は0x04です。
動作的に問題はありませんが、最後のクロックの立ち下がりの早さよ。
以上RSPIとSCIのマスターモードでの使用例でした。スレーブモードは使う機会があれば。
また今回スレーブとして使用したatmega328PのSPI通信も簡単に記載したいと思います。ただマニュアルにコード例まで記載してあるので、あえて残す意味があるのかといわれるとおそらく無い。






