AVRのSPI


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_kairo.gif

回路図


/************************/
/*  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);
}


真空管
戻る