2020年2月28日金曜日

RX220のSPI通信(マスターモード)

RX220でSPI通信を使用する方法として、シリアルペリフェラルインタフェース(RSPI)とシリアルコミュニケーションインタフェース(SCI)の2つの機能があります。
RSPIは名前の通りSPI専用の機能であり設定可能な項目が多いです。でも1チャネルしかないです。
SCIはハードウェアマニュアルにも簡易SPI機能とあるように設定が少ないです。でも5チャネルあります。
SCIでも機能は十分だと思うので、状況に合わせて好きな方を使えば良いと思います。 今回は都合で両方使ってみたので両方の機能をマスターモードで動作させたときの非常にシンプルな使用例をメモします。

条件

  • 動作:マスターマイコンとスレーブマイコン間で1バイトのSPI通信の送信・受信
  • マスターマイコン:R5F52206BDFM(秋月で売ってるやつ)
  • スレーブマイコン:atmega328P-PU(秋月で売ってるやつ)
  • 開発環境:e2studio/Renesas Flash Programmer

回路

それぞれのSPI通信ピンに接続しただけです。RX220は秋月のマイコンボード使用しているのでチップのピン番号ではありません。
今回一対一想定のためスレーブのSSピンはGNDに落としてます。


使用例

ありがたいことにハードウェアマニュアルに初期化、送信、受信のフロー例が全て記載されているため、それに従って記載するだけです。だけのはず。

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通信例です。


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通信も簡単に記載したいと思います。ただマニュアルにコード例まで記載してあるので、あえて残す意味があるのかといわれるとおそらく無い。

2020年1月14日火曜日

[動画]レーザー級レーザポインター


アージュ20周年おめでとう!ということで勝手に盛り上がって作りました。


動画編集がめんどくさくてまんまあげましたけど、やはりこれは味気ないですな。

追記:マブラヴの原作者である吉宗さんがツイッターでなんでもかんでも反応してくれる時期があったので便乗して反応いただきました!ありがたい!

  • 構成
    概形
足の方
    レーザ出力部の正面図
  • 機能
①照射スイッチを押すと徐々に目が白色に光りはじめる(ほぼわからない)

②照射スイッチを押して3秒後レーザー出力と照射音が再生される

③照射スイッチを押している間、レーザー出力し続ける

というのが動画の機能です。 ただこれでは実用性が無いので、モード切替スイッチを押すと照射スイッチを押している間は片方のレーザー出力だけするモードに切り替わるようにしてます。


せっかくだし会社でのプレゼン用にと思ってましたが、サイズが大きくなりすぎてさすがに目立ちすぎますね。 次作るときは手のひらサイズに小型化したいです。

クリスタルレジンの処理

クリスタルレジンを初めて使用したのでメモ。

レーザー級レーザーポインターの目の部分の作成に使いました。

クリスタルレジンに黒着色して作成しています。
クリスタルレジンはプロクリスタル880、着色剤はいろどろっぷという製品を使っています。
これは固めてるときの画像ですが、電池を刺しているのはレーザモジュールを刺す用の穴を作るためです。型というか受け皿になっている白いやつはグルーです。大体一日たてばしっかり固まりますが、配合比がてきとーすぎると永遠に固まりません。

グルーガンで直径3cmくらいのスーパーボールにグルーを塗りたくり型として使いました。表面はなかなか荒いですが、紙やすりで240~2000番くらいを順々にかけて100均のクリアラッカーをかけました。よくみると傷が結構残っていますが、個人的には十分テカテカになりました。

100均で何とかしたがりすぎな感じしますね。

2016年1月24日日曜日

[動画]武御雷のプラモにLED仕込んでみた

初めての製作動画?をアップロードしました。



再生・コメント・マイリスして下さったみなさんありがとうございます。配線が短いということにコメントで初めて気づきました。

詳細は動画を見てもらえればと思いますが、簡単に構成をば。

武御雷インジケーター
  • 構成
大きく分けて基盤とLEDがのったプラモ(武御雷LED)に分かれます。武御雷LEDは機能的に見ればただのLEDです。基盤で色々処理してその結果でLEDを光らせてます。


  • 機能
トグルスイッチでインジケーターモードとボリュームモードが選択できます。

インジケーターモード:
基盤でスマホを充電してるかどうかを電流を測定することによって検知し、武御雷のLEDを光らせます。電池の残量によって武御雷の発光具合が変わります。電池容量が少ないと武御雷はMAXで充電進んでいくと暗くなっていき、終わると消えます。いや消すつもりでした。実際は充電終わっても電流が少し流れてるらしくチカチカします。まぁわかるといえばわかるのでいいです。

ボリュームモード:
とりあえずLED点灯。ボリューム回すことによって発光具合をボディとジャンプユニットで別々に調整できます。まぁ使いません。