AVRのSPIの実験をしてみました。 プログラムの初期設定は @ポートの設定は下表のようにする。 AマスターはSPCRレジスタのSPE, MSTR, SPR0を1にする。(SCK = システムクロック / 16) BスレーブはSPCRレジスタのSPIE, SPEを1にする。 以上です。 マスターは @スレーブの/SSにつながっている出力ポートをローにする。 A送信データをSPDRレジスタに書く。 SCK(8クロック)が自動的に出てマスターのデータが送信されるのと同時に、スレーブのデータをSPDRへ受信する。 Bこの送受信が終わるとSPSRレジスタのSPIF(スレーブ側も)が立つ。 (このレジスタを読んだ後、SPDRをアクセスすることによってクリアされる。) Cスレーブの受信処理の時間を待つ (マスター側からは処理の時間がわからないので十分なディレイ入れる。 この実験では100マイクロ秒のディレイを入れました。) 送りたいバイト数分、ABCを繰り返す。 D@をハイにして終わる。 この実験ではSCK = システムクロック / 2はだめでした。SCK = システムクロック / 4以下はOKです。 なお、一回目の受信データは不定です。 一回目の送信はスレーブへのコマンドとしたらどうでしょう。 二回目以降はスレーブで前回に設定データ、設定がなければマスターが前回送ったデータを受信します。 スレーブは プログラムの初期設定のBのように、SPIFが立つと割り込みがかかるように設定します。 割り込みルーチン内でマスタ−より送られてきたデータをSPDRから読み、 マスターへ送るデータをSPDRへ書き込みます。 |
PIN名 | マスター | スレーブ |
---|---|---|
SCK | 出力 | 入力 |
MISO | 入力 | 出力 |
MOSI | 出力 | 入力 |
/SS | 出力 注1 | 入力 注2 |
注1 普通の出力ポート (/SSでなくても)でも良い
注2 必ず/SSポートを使用する(入力ローでスレーブのMISOは出力、
入力ハイでMISOはハイインピーダンスになります)
回路図
/************************/ /* avr_spi.c */ /* */ /* V1.0 2014/07/15 */ /************************/ #include <avr/io.h> #include "avr_spi.h" void initSPI_master(void) { /// SPCR = _BV(SPE) | _BV(MSTR); SPSR = _BV(SPI2X); /* SPI許可, MASTER, fosc / 2 */ /// SPCR = _BV(SPE) | _BV(MSTR); /* SPI許可, MASTER, fosc / 4 */ /// SPCR = _BV(SPE) | _BV(MSTR) | _BV(SPR0); SPSR = _BV(SPI2X); /* SPI許可, MASTER, fosc / 8 */ SPCR = _BV(SPE) | _BV(MSTR) | _BV(SPR0); /* SPI許可, MASTER, fosc / 16 */ } unsigned char tx_SPI_master(unsigned char tx_data) { SPDR = tx_data; while((SPSR & _BV(SPIF)) == 0) ; return SPDR; } void initSPI_slave(void) { SPCR = _BV(SPIE) + _BV(SPE); } |