概要
EEPROM (Electrically Erasable Programmable Read-Only Memory) は、電気的に消去、書き込み可能な不揮発性メモリの1種である。
EEPROMの主な特徴を以下に示す。
- 不揮発性
- 電源を切ってもデータを保持できる。
- 書き換え可能
- データの消去と書き込みを電気的に行うことができる。
- バイト単位のアクセス
- バイト単位でデータの読み書きが可能である。
- 書き換え回数の制限
- 一般的に、100万回程度の書き換えが可能である。
- 低速
- フラッシュメモリ等と比較して、読み書きの速度が遅い。
- シリアル通信
- I2CやSPI等のシリアル通信インターフェースを使用して、マイクロコントローラと通信する。
- 容量
- 数[Kbit]〜数[Mbit]までの容量のデバイスが存在する。
- 用途
- 設定情報や較正データの保存、データロガー、小容量のデータ保存等に使用される。
EEPROMは、マイコンのシステムで、不揮発性のデータ保存が必要な場合に広く使用されている。
フラッシュメモリと比較して書き換え回数が多く、バイト単位のアクセスが可能な点が特徴である。
ただし、書き換え速度が遅く、大容量のデータ保存には向かない。
また、書き換え回数にも制限があるため、頻繁に更新されるデータの保存には適していない。
したがって、用途に応じて、EEPROM、フラッシュメモリ、SRAM等の他のメモリデバイスを使い分ける必要がある。
マイコンの内蔵メモリでデータ保存が可能な場合は、外付けのEEPROMを使用しないこともある。
EEPROMは、マイコンのシステムにおいて、小容量の不揮発性データ保存が必要な場合に重要な役割を果たすデバイスである。
EEPROMの種類
一般的に、外付けのEEPROMとして使用されているデバイスには、以下に示すようなものがある。
以下に示すEEPROMは、MSP430F149マイコンのI2CまたはSPIインターフェースに直接接続して使用することができる。
容量や速度、インターフェースの種類などの要件に応じて選択する。
特に、24LC256は、比較的大容量でI2Cインターフェースを備えているため、MSP430F149マイコンの組み合わせで広く使用されている人気の高いEEPROMの1つである。
24LC256 (256Kbit I2C EEPROM)
- Microchip社製の不揮発性メモリ
- I2Cインターフェースを使用
- 32[KB] (256[Kbit]) の容量
- 低消費電力で動作
25LC640A (64Kbit SPI EEPROM)
- Microchip社製の不揮発性メモリ
- SPIインターフェースを使用
- 8[KB] (64[Kbit]) の容量
- 高速動作が可能
AT24C32 (32Kbit I2C EEPROM)
- Atmel (現Microchip) 社製の不揮発性メモリ
- I2Cインターフェースを使用
- 4[KB] (32[Kbit]) の容量
- industryグレードの信頼性
MSP430F149とEEPROMの接続
MSP430F149マイコンは、USART0モジュールを使用してI2CまたはSPI通信を行うことができる。
I2C接続
MSP430F149のUSART0モジュールをI2Cモードで使用する場合、以下のピンを使用する。
- P3.1 - SDA (I2Cデータライン)
- P3.3 - SCL (I2Cクロックライン)
I2C通信では、SDAとSCLの両方のラインに外部プルアップ抵抗 (通常4.7[kΩ]~10[kΩ]) が必要である。
複数のデバイスをI2Cバスに接続する場合は、それぞれのデバイスに異なるアドレスを設定する。
SPI接続
MSP430F149のUSART0モジュールをSPIモードで使用する場合、以下のピンを使用する。
- P3.1 - SIMO (マスタ出力、スレーブ入力)
- P3.2 - SOMI (マスタ入力、スレーブ出力)
- P3.3 - UCLK (SPIクロック)
- P3.0 - CS (チップセレクト、GPIO制御)
SPI通信では、チップセレクト (CS) 信号は通常のGPIOピンを使用して制御する。
複数のSPIデバイスを接続する場合は、それぞれに異なるCSピンを割り当てる。
サンプルコード
24LC256 (256Kbit I2C EEPROM)
以下の例では、I2C通信を使用してEEPROMとの通信を行っている。
I2C通信を初期化した後、i2c_write_byte関数を使用してEEPROMにデータを書き込み、i2c_read_byte関数を使用して書き込んだデータを読み出している。
- i2c_init関数でI2Cの初期化を行う。
ピンの設定、I2Cの設定、クロック周波数の設定等を行う。
MSP430F149マイコンのP3.1をSDA、P3.3をSCLに指定している。 - i2c_write_byte関数を使用して、指定したアドレスにデータを書き込む。
スタートコンディション、アドレスの送信、データの送信、ストップコンディションの順に処理を行う。 - i2c_read_byte関数を使用して、指定したアドレスからデータを読み出す。
スタートコンディション、アドレスの送信、再スタートコンディション、データの受信、ストップコンディションの順に処理を行う。
実際に動作させる場合は、回路の接続や電源の供給等にも注意が必要である。
特に、I2C通信では、SDAとSCLのラインに4.7[kΩ]~10[kΩ]のプルアップ抵抗を接続する必要がある。
下図に、MSP430F149と24LC256のシーケンス図を示す。
#include <msp430f149.h>
// 24LC256のI2Cアドレス
// 24LC256のA0, A1, A2ピンがGNDに接続されている場合
#define EEPROM_ADDRESS 0x50
void i2c_init();
void i2c_write_byte(unsigned int address, unsigned char data);
unsigned char i2c_read_byte(unsigned int address);
int main(void)
{
WDTCTL = WDTPW | WDTHOLD; // ウォッチドッグタイマを停止
// DCOクロック設定 (約8MHz)
DCOCTL = DCO0 | DCO1 | DCO2;
BCSCTL1 = RSEL0 | RSEL1 | RSEL2;
i2c_init(); // I2Cの初期化
unsigned char data = 0xAA; // 書き込むデータ
unsigned int address = 0x0010; // EEPROMのメモリアドレス
i2c_write_byte(address, data); // EEPROMにデータを書き込み
__delay_cycles(50000); // 書き込み完了待機 (約5ms)
unsigned char read_data = i2c_read_byte(address); // EEPROMからデータを読み出し
while(1);
}
void i2c_init()
{
P3SEL |= 0x0A; // P3.1(SDA)とP3.3(SCL)をI2C機能に割り当て
U0CTL |= I2C | SYNC; // I2Cモードを選択、同期モード
U0CTL &= ~I2CEN; // I2Cモジュールを一時的に無効化
I2CTCTL = I2CSSEL1; // SMCLK (サブマスタークロック) を選択
I2CPSC = 0x00; // プリスケーラなし
I2CSCLH = 0x50; // SCL高期間設定
I2CSCLL = 0x50; // SCL低期間設定 (約100kHz)
I2COA = 0x01A5; // 自身のアドレスを設定
I2CSA = EEPROM_ADDRESS; // スレーブアドレス (EEPROM) を設定
U0CTL |= I2CEN; // I2Cモジュールを有効化
}
void i2c_write_byte(unsigned int address, unsigned char data)
{
while (I2CDCTL & I2CBUSY); // バスがアイドル状態になるまで待機
I2CTCTL |= I2CTRX | I2CSTT; // 送信モード、スタートコンディション生成
while ((I2CIFG & TXRDYIFG) == 0); // 送信準備完了待ち
I2CDRB = (address >> 8) & 0xFF; // アドレス上位バイトの送信
while ((I2CIFG & TXRDYIFG) == 0);
I2CDRB = address & 0xFF; // アドレス下位バイトの送信
while ((I2CIFG & TXRDYIFG) == 0);
I2CDRB = data; // データの送信
while ((I2CIFG & TXRDYIFG) == 0);
I2CTCTL |= I2CSTP; // ストップコンディションの送信
while (I2CDCTL & I2CBUSY); // 転送完了まで待機
}
unsigned char i2c_read_byte(unsigned int address)
{
unsigned char data;
while (I2CDCTL & I2CBUSY); // バスがアイドル状態になるまで待機
I2CTCTL |= I2CTRX | I2CSTT; // 送信モード、スタートコンディション生成
while ((I2CIFG & TXRDYIFG) == 0);
I2CDRB = (address >> 8) & 0xFF; // アドレス上位バイトの送信
while ((I2CIFG & TXRDYIFG) == 0);
I2CDRB = address & 0xFF; // アドレス下位バイトの送信
while (I2CTCTL & I2CSTT); // スタートコンディション送信完了待ち
I2CTCTL &= ~I2CTRX; // 受信モードに設定
I2CTCTL |= I2CSTT; // 再スタートコンディション生成
while (I2CTCTL & I2CSTT); // スタートコンディション送信完了待ち
I2CTCTL |= I2CSTP; // ストップコンディション設定
while ((I2CIFG & RXRDYIFG) == 0); // 受信完了まで待機
data = I2CDRB; // 受信データの読み出し
while (I2CDCTL & I2CBUSY); // 転送完了まで待機
return data;
}
25LC640A (64Kbit SPI EEPROM)
以下の例では、SPI通信を使用してEEPROMとの通信を行っている。
SPIの初期化後、eeprom_write_byte関数を使用してEEPROMにデータを書き込み、eeprom_read_byte関数を使用して書き込んだデータを読み出している。
- spi_init関数でSPIの初期化を行う。
ピンの設定、SPIの設定、クロック周波数の設定等を行う。
MSP430F149マイコンのP3.1をSIMO、P3.2をSOMI、P3.3をUCLKに指定している。 - eeprom_write_byte関数を使用して、指定したアドレスにデータを書き込む。
WRENコマンドで書き込み有効化して、WRITEコマンドでアドレスとデータを送信する。 - eeprom_read_byte関数を使用して、指定したアドレスからデータを読み出す。
READコマンドでアドレスを送信して、データを受信する。
実際に動作させる場合は、回路の接続や電源の供給等にも注意が必要である。
特に、25LC640AのCS (チップセレクト) ピンは、適切なポートピンに接続して、ソースコード内で設定する必要がある。
下図に、MSP430F149と25LC640Aのシーケンス図を示す。
#include <msp430f149.h>
// CSピンの設定 (例: P3.0)
#define EEPROM_CS_PIN BIT0
#define CS_LOW() P3OUT &= ~EEPROM_CS_PIN
#define CS_HIGH() P3OUT |= EEPROM_CS_PIN
// SPI EEPROM命令コード
#define EEPROM_CMD_READ 0x03
#define EEPROM_CMD_WRITE 0x02
#define EEPROM_CMD_WREN 0x06
#define EEPROM_CMD_RDSR 0x05
void spi_init();
unsigned char spi_transfer(unsigned char data);
void eeprom_write_byte(unsigned int address, unsigned char data);
unsigned char eeprom_read_byte(unsigned int address);
unsigned char eeprom_read_status();
void eeprom_wait_ready();
int main(void)
{
WDTCTL = WDTPW | WDTHOLD; // ウォッチドッグタイマーを停止
// DCOクロック設定 (約8MHz)
DCOCTL = DCO0 | DCO1 | DCO2;
BCSCTL1 = RSEL0 | RSEL1 | RSEL2;
P3DIR |= EEPROM_CS_PIN; // CSピンを出力に設定
CS_HIGH(); // CSピンをハイに設定
spi_init(); // SPIの初期化
unsigned char data = 0xAA; // 書き込むデータ
unsigned int address = 0x1000; // EEPROMのメモリアドレス
eeprom_write_byte(address, data); // EEPROMにデータを書き込み
unsigned char read_data = eeprom_read_byte(address); // EEPROMからデータを読み出し
while(1); // 無限ループ
}
void spi_init()
{
P3SEL |= 0x0E; // P3.1, P3.2, P3.3をSPI機能に割り当て
U0CTL = SWRST; // USARTをリセット状態に
U0CTL |= CHAR | SYNC | MM; // 8ビット、同期モード、マスタモード
U0TCTL = CKPL | SSEL1 | STC; // クロック極性、SMCLK選択、3ピンモード
U0BR0 = 0x02; // ボーレート分周設定 (約4MHz)
U0BR1 = 0x00;
U0MCTL = 0x00; // 変調制御 (SPIでは未使用)
ME1 |= USPIE0; // USARTモジュール有効化
U0CTL &= ~SWRST; // USARTの動作を開始
}
unsigned char spi_transfer(unsigned char data)
{
while ((IFG1 & UTXIFG0) == 0); // 送信バッファが空になるまで待機
U0TXBUF = data; // データを送信バッファに書き込み
while ((IFG1 & URXIFG0) == 0); // 受信完了まで待機
return U0RXBUF; // 受信データを返す
}
unsigned char eeprom_read_status()
{
unsigned char status;
CS_LOW(); // EEPROM選択
spi_transfer(EEPROM_CMD_RDSR); // ステータス読み込みコマンド送信
status = spi_transfer(0xFF); // ステータス値受信
CS_HIGH(); // EEPROM非選択
return status;
}
void eeprom_wait_ready()
{
while (eeprom_read_status() & 0x01) // WIPビットが0になるまで待機
{
__delay_cycles(100);
}
}
void eeprom_write_byte(unsigned int address, unsigned char data)
{
eeprom_wait_ready(); // 前回の書き込み完了待機
CS_LOW(); // EEPROM選択
spi_transfer(EEPROM_CMD_WREN); // 書き込み有効化コマンド
CS_HIGH(); // EEPROM非選択
__delay_cycles(100); // 短い待機
CS_LOW(); // EEPROM選択
spi_transfer(EEPROM_CMD_WRITE); // 書き込みコマンド
spi_transfer((address >> 8) & 0xFF); // アドレス上位バイト
spi_transfer(address & 0xFF); // アドレス下位バイト
spi_transfer(data); // データ
CS_HIGH(); // EEPROM非選択
eeprom_wait_ready(); // 書き込み完了待機
}
unsigned char eeprom_read_byte(unsigned int address)
{
unsigned char data;
eeprom_wait_ready(); // 書き込み完了待機
CS_LOW(); // EEPROM選択
spi_transfer(EEPROM_CMD_READ); // 読み出しコマンド
spi_transfer((address >> 8) & 0xFF); // アドレス上位バイト
spi_transfer(address & 0xFF); // アドレス下位バイト
data = spi_transfer(0xFF); // データ受信
CS_HIGH(); // EEPROM非選択
return data;
}
AT24C32 (32Kbit I2C EEPROM)
AT24C32 EEPROMを使用してI2C通信する場合は、上記の24LC256のサンプルプログラムとほぼ同じとなる。
これは、AT24C32と24LC256がどちらもI2Cインターフェースを使用しており、通信プロトコルが同一だからである。
主な違いは、EEPROMの容量とアドレッシングである。
- 24LC256は、256[Kbit] (32[KB]) の容量を持ち、16ビットのアドレス (0x0000~0x7FFF) を使用する。
- AT24C32は、32[Kbit] (4[KB]) の容量を持ち、12ビットのアドレス (0x000~0xFFF) を使用する。
AT24C32のアドレッシングは2バイトで行われるが、有効なアドレス範囲は0x000~0xFFFであり、上位4ビットは無視される。
したがって、24LC256向けのサンプルコードをそのままAT24C32で使用することができる。
ただし、EEPROMの容量が異なるため、アドレスの範囲に注意が必要である。
AT24C32の有効なアドレス範囲は、0x000~0xFFFであり、それ以外のアドレスを指定した場合の動作は未定義となることに注意する。
また、EEPROMのI2Cアドレスを確認して、必要に応じて、EEPROM_ADDRESSの定義を変更する必要がある。
AT24C32のデフォルトのI2Cアドレスは0x50 (A0、A1、A2がGNDに接続されている場合) だが、実装により異なる場合がある。
注意事項
MSP430F149マイコンを使用してEEPROMと通信する場合には、以下に示す事柄に注意する。
共通
- 電源電圧
- EEPROMの動作電圧範囲を確認し、MSP430F149の電源電圧と一致していることを確認する。
- デカップリングコンデンサ
- EEPROMの電源ピンの近くに、0.1[μF]のデカップリングコンデンサを配置する。
- 配線長
- I2CおよびSPIの信号線は、できるだけ短く、かつノイズの影響を受けにくいように配線する。
- エラー処理
- 実際のアプリケーションでは、通信エラーや書き込みエラーに対する適切なエラー処理を実装する必要がある。
I2C通信
- プルアップ抵抗
- I2CのSDAとSCLのラインには、必ず外部プルアップ抵抗 (4.7[kΩ]~10[kΩ]) を接続する必要がある。
- クロック周波数
- I2C通信のクロック周波数は、標準モードで100[kHz]、高速モードで400[kHz]までサポートされている。
- 書き込み完了時間
- EEPROMへの書き込み後、内部書き込みサイクルが完了するまで約5[ms]の待機時間が必要である。
- アドレッシング
- 16ビットアドレスのEEPROMでは、アドレスを2バイトで送信する必要がある。
SPI通信
- チップセレクト制御
- SPI通信では、通信前にCS信号をLOWに、通信後にHIGHにする必要がある。
- クロック極性と位相
- SPIのクロック極性と位相は、EEPROMのデータシートに従って設定する必要がある。
- 書き込み有効化
- EEPROMへの書き込み前に、必ずWRENコマンドで書き込みを有効化する必要がある。
- ステータス確認
- 書き込み操作後、ステータスレジスタを読み取り、WIPビットが0になるまで待機する必要がある。