AVRのSPIモジュール / EEPROM 25LC256 / とにかく何かを書き込んで読み出してみる

pp.339ff.
今度は、テキストが題材にしているEEPROM 25LC256を試してみる。とりあえず何かを書き込んでそれを読み出してみる。
f:id:ti-nspire:20200115094500p:plain:h280 f:id:ti-nspire:20200115094514j:plain:h280 f:id:ti-nspire:20200115094401p:plain:h280
f:id:ti-nspire:20200116055819p:plain
f:id:ti-nspire:20200116060027p:plain

#include <avr/io.h>
#include <util/delay.h>
extern "C" {
    #include "USART.h"
}

int main(){
    DDRB  |= (1 << PB2); // PB2を!SS端子(OUT)として使う。
    PORTB |= (1 << PB2); // 最初はスレーブセレクトを解除しておく(Hを出力しておく)。
    DDRB  |= (1 << PB3); // PB3をMOSI端子(OUT)として使う。
    PORTB |= (1 << PB4); // PB4をMISO端子(IN)として使う。内部プルアップしておく。
    DDRB  |= (1 << PB5); // PB5をSCK端子(OUT)として使う。

    //SPCR &= ~(1 << CPOL | 1 << CPHA);           // mode(0,0)。デフォルト。CPOL、CPHAのCはclock。
    //SPCR &= ~(1 << CPOL); SPCR |=  (1 << CPHA); // mode(0,1)
    //SPCR |=  (1 << CPOL); SPCR &= ~(1 << CPHA); // mode(1,0)
    //SPCR |=  (1 << CPOL | 1 << CPHA);           // mode(1,1)

    //SPCR &= ~(1 << DORD); // MSBファーストで転送する。デフォルト。
    //SPCR |=  (1 << DORD); // LSBファーストで転送する。

    SPCR |= (1 << SPR1 | 1 << SPR0); // SPIのクロック周波数。ここでは8MHzを128分周した(62.5kHz)。SPRのRはRate。
    SPCR |= (1 << MSTR);             // AVRをマスターにする。
    SPCR |= (1 << SPE);              // SPIを有効化する。

    /******************************************/
    /* ためしに何かを書き込んで読み出してみる */
    /******************************************/
    initUSART();

    uint16_t address   ; // 0~0d32767 (0~0x7fff)番地
    uint8_t  hi_address;
    uint8_t  lo_address;

    uint8_t data; // 0~0d255 (0~0xff)

    while(1){
        printString("Enter an address in decimal: ");
        address    = getNumber16();
        hi_address = (uint8_t)(address >> 8);
        lo_address = (uint8_t) address;

        printString("Enter a data in decimal: ");
        data = getNumber();
        
        PORTB &= ~(1 << PB2)             ; // スレーブをセレクトして、
        SPDR = 0b00000110                ; // 書き込み有効化命令を送って、
        loop_until_bit_is_set(SPSR, SPIF); // 転送終了を待って、
        PORTB |= (1 << PB2)              ; // スレーブセレクトを解除して、

        PORTB &= ~(1 << PB2)             ; // スレーブをセレクトして、
        SPDR = 0b00000010                ; // 書き込み命令を送って、
        loop_until_bit_is_set(SPSR, SPIF); // 転送終了を待って、
        SPDR = hi_address                ; // アドレスの上位バイトを送って,
        loop_until_bit_is_set(SPSR, SPIF); // 転送終了を待って、
        SPDR = lo_address                ; // アドレスの下位バイトを送って、
        loop_until_bit_is_set(SPSR, SPIF); // 転送終了を待って、
        SPDR = data                      ; // 書き込む値を送って、
        loop_until_bit_is_set(SPSR, SPIF); // 転送終了を待って、
        PORTB |= (1 << PB2)              ; // スレーブセレクトを解除して、
        _delay_ms(20)                    ; // メモリーへの書き込みが終わるのを待って(5ms程度必要)、

        PORTB &= ~(1 << PB2)             ; // スレーブをセレクトして、
        SPDR = 0b00000011                ; // 読み出し命令を送って、
        loop_until_bit_is_set(SPSR, SPIF); // 転送終了を待って、
        SPDR = hi_address                ; // アドレスの上位バイトを送って、
        loop_until_bit_is_set(SPSR, SPIF); // 転送終了を待って、
        SPDR = lo_address                ; // アドレスの下位バイトを送って、
        loop_until_bit_is_set(SPSR, SPIF); // 転送終了を待って、
        SPDR = 0                         ; // ダミーデータを送って、
        loop_until_bit_is_set(SPSR, SPIF); // 転送終了を待って、
        PORTB |= (1 << PB2)              ; // スレーブセレクトを解除して、

        printString("0d");
        printByte(SPDR)                  ; // 読み出された値を表示する。
        printString(" written at 0d");
        printWord(address);
        printString(".\n\n");
    }

    return 0;
}