Microchip Technology Inc. 24AA1025 / 24LC1025 / 24FC1025(24XX1025)は、128K x 8(1024Kビット)のシリアル電気的消去可能PROMで、幅広い電圧範囲(1.8V〜5.5V)で動作できます。パーソナルコミュニケーションやデータ収集などの高度な低電力アプリケーション用に開発されました。
このデバイスは、バイト毎のランダム書き込みと最大128バイトデータのページ書き込み機能の両方を備えています。読み出しは、ランダム読み出しと連続読み出しの両方が可能です。ただし連続読み出しは、0000h〜FFFFhおよび10000h〜1FFFFh範囲内に限定され、これら2範囲をまたぐ連続読み出しはできません。一つの物理デバイスに2つの512Kビットメモリを入れた構成です。同じI2Cデータバス上に最大4つのデバイス、8つのメモリ範囲を接続可能なので、最大4 MビットのシステムEEPROMメモリが実現できます。
デバイス選択表:
品番 | VCC範囲 | 最大クロック周波数 | 温度範囲 |
---|---|---|---|
24AA1025 | 1.7-5.5V | 400 kHz† | I |
24LC1025 | 2.5〜5.5V | 400 kHz ※ | I、E |
24FC1025 | 2.5〜5.5V | 1 MHz | I |
† | VCC < 2.5Vの場合は100 kHz。 |
※ | VCC < 4.5V、E 温度範囲で100 kHz |
I | -40°C〜+ 85°C Industrial |
E | -40°C〜+ 125°C Automotive |
A0、A1入力は、複数の24XX1025デバイスを接続するために使用されます。これらの入力のレベルは、I2Cスレーブアドレスの対応ビットと比較されます。比較が真の場合、チップが選択されます。
異なるチップセレクトビットの組み合わせを使用して、最大4つのデバイスを同じバスに接続できます。ほとんどのアプリケーションでは、チップアドレス入力A0およびA1は、論理「0」または論理「1」にハードワイヤードされています。
A2入力はI2Cスレーブアドレスに設定機能のないチップセレクトです。デバイスを動作させるには、このピンをVCCに接続する必要があります。
アドレスやデータをデバイス間で転送するために使用される双方向ピンです。SDAバスはオープンドレイン端子のため、VCCへのプルアップ抵抗が必要です(通常 100 kHzの場合は 10kΩ、400 kHzおよび 1 MHzの場合は 2kΩ)。
通常のデータ転送では、SDAはSCLがローの時だけ変更可能です。SCLがハイの時の変更は、[Start condition]か[Stop condition]を意味しています。
この入力は、デバイス間データ転送の同期のために使用されます。
このピンは、VSSまたはVCCに接続します。VSSに接続すると、書き込み操作が有効になり、VCCに接続すると書き込みは禁止されます。読み出し操作には影響を与えません。
24XX1025は、双方向2線式伝送プロトコルをサポートしています。バス上にデータを送信するデバイスはトランスミッターと定義され、データを受信するデバイスはレシーバーと定義されます。バスは、シリアルクロック(SCL)、[Start condition]および[Stop condition]を生成するマスターデバイスによって制御され、24XX1025はスレーブとして動作します。マスターもスレーブもトランスミッターモードまたはレシーバーモードのどちらのモードでも動作しますが、どのモードで動作するかはマスターデバイスが決定します。
次のバスプロトコルが定義されています。
したがって、以下のバス条件が定義されています(図4-1)。
データラインとクロックラインの両方がハイ電位のままです。
クロック(SCL)がハイ電位の時の、SDAラインのハイからロー電位への遷移を[Start condition]と言います。すべてのコマンドの前には、[Start condition]が必要です。
クロック(SCL)がハイ電位のときの、SDAラインのローからハイ電位への遷移を[Stop condition]と言います。すべての操作は[Stop condition]で終了する必要があります。
[Start condition]の後、クロックのハイ電位期間、データラインが安定している状態なら、データラインは有効なデータを表します。ライン上のデータは、クロック信号がロー電位の時に変更する必要があります。クロックパルスごとに1ビットのデータを取り扱います。
各データ転送は、[Start condition]で開始され、[Stop condition]で終了します。[Start condition]と[Stop condition]の間に転送されるデータバイト数は、マスターデバイスによって決定されます。
各受信デバイスは、アドレス指定されると、各バイトの受信後にAcknowledge[ACK]信号を生成する必要があります。マスターデバイスは、この[Acknowledge]ビット用の追加のクロックパルスを生成する必要があります。
Note:
24XX1025 は、内部で書き込みサイクル実行中には、書き込みサイクル開始の適切な制御バイトを受信しても、[Acknowledge]ビットを生成しません。
応答するデバイスは、[Acknowledge]クロックパルス中は、SDAラインをプルダウンする必要があります。こうすることで、[Acknowledge]用クロックパルスのハイ電位期間中はSDAラインをロー電位に安定させます。セットアップ時間とホールド時間を考慮する必要があります。
読み出し中、マスターは、スレーブからクロック出力された最後のバイトで[Acknowledge]ビットを生成しないことで、データの終わりをスレーブに通知します。この場合、スレーブ(24XX1025)はデータラインをハイ電位のままにし、マスターが[Stop condition]を生成できるようにします。
(注1) トランスミッターはこの時点でSDAラインを解放する必要があります。これにより、レシーバーはSDAラインをロー電位にプルダウンして、前の8ビットのデータを[Acknowledge]できます。
(注2) トランスミッターがデータを送信し続けることができるように、レシーバーはこの時点でSDAラインを解放する必要があります。
制御バイトとは、マスターデバイスからの[Start condition]に続いて受信される最初のバイトです(図5-1)。制御バイトは4ビットの制御コードで構成されます。24XX1025の場合、読み出し操作、書き込み操作は共に「1010」バイナリに設定されています。制御バイトの次のビットは、ブロック選択ビット(B0)で、アレイ全体にアクセスするためのA16アドレスビットとして機能します。制御バイトの次の2ビットは、チップセレクトビット(A1、A0)です。チップセレクトビットを使用すると、同じバス上で最大4つの24XX1025デバイスを接続し、アクセスするデバイスを選択できます。デバイスが応答するには、制御バイトのチップセレクトビットが対応するA1およびA0ピンのロジックレベルに対応している必要があります。これらのビットは、事実上、ワードアドレスの最上位2ビットです。
制御バイトの最後のビットは、実行さする操作を定義します。「1」に設定すると、読み出し操作が選択され、「0」に設定すると、書き込み操作が選択されます。受信した次の2バイトは、最初のデータバイトのアドレスを定義します(図5-2)。上位アドレスビットが最初に転送され、次に下位ビットが転送されます。
[Start condition]に続いて、24XX1025はSDAバスを監視して、送信されているデバイスタイプ識別子をチェックします。「1010」コードと適切なデバイス選択ビットを受信すると、スレーブデバイスはSDAラインに[Acknowledge]信号を出力します。R / Wビットの状態に応じて、24XX1025は読み出しまたは書き込み操作を選択します。
このデバイスには、512Kビットの2つのセグメントに分割される内部アドレス指定境界の制限があります。ブロック選択ビット「B0」で、どちらのセグメントへアクセスするのかを制御します。
チップセレクトビットA1、A0は、同じバス上に最大4つの24XX1025を追加することにより、最大4 Mbitの連続アドレス空間を拡張するために使用できます。この場合、ソフトウェアは制御バイトのA0をアドレスビットA16として、A1をアドレスビットA17として使用できます。デバイスの境界を越えて連続して読み取ることはできません。
各デバイスには、内部アドレス指定境界の制限があります。これにより512Kビットの2つのセグメントに分割されます。ブロック選択ビット「B0」は、どちらの「半分」へアクセスするかを制御します。
連続読み出し操作は512Kブロック内に制限されています。同じバス上の4つのデバイスを読み取るには、8つのランダムな読み出しコマンドを指定する必要があります。
マスターは、[Start condition]に続けて、制御コード(4ビット)、ブロック選択(1ビット)、チップ選択(2ビット)、およびR / Wビット(ロジックLOW)をクロックでバスに送出されます。アドレス指定されたスレーブレシーバーは、9番目のクロックサイクル中に[Acknowledge]ビットを生成します。マスターは、続けてアドレス上位バイトを送信します。
マスターが送信する次のバイトはワードアドレスの上位バイトとして、24XX1025のアドレスポインターに書き込まれます。次のバイトは最下位アドレスバイトです。24XX1025からACK信号を受信した後、マスターデバイスは書き込み対象のデータワードを送信します。24XX1025が再度[Acknowledge]を送信し、マスターは、[Stop condition]を生成します。これにより内部書き込みサイクルが開始されます。
内部書き込みサイクル実行中は、書き込みの開始の適切な制御バイトでポーリングされても、24XX1025は[Acknowledge]信号を生成しません(図6-1)。
WPピンをハイ電位に保持したまま書き込みを行おうとすると、デバイスはコマンドを認識しますが、書き込みサイクルは発生せず、データは書き込まれず、デバイスは新しいコマンドをすぐに受け入る状態になります。バイト書き込みコマンドの後、内部アドレスカウンターは、書き込まれたばかりのアドレスの次のアドレス位置を指します。
書き込み制御バイト、ワードアドレス、最初のデータバイトは、バイト書き込みと同じ方法で24XX1025に送信されます。ただし、マスターは[Stop condition]を生成する代わりに、最大127バイトを追加で送信します。これらのバイトはチップ内のページバッファーに一時的に格納され、マスターが[Stop condition]を送信した後にメモリに書き込まれます。データワードを受信すると、7ビットの下位アドレスポインタが内部で1ずつインクリメントされます。マスターが[Stop condition]を生成する前に128バイト以上のデータを送信すると、アドレスカウンターがロールオーバーし、以前に受信したデータが上書きされます。[Stop condition]が受信されると、バイト書き込み操作と同様に、内部書き込みサイクルが動作開始します(図6-2)。WPピンをハイ電位に保持したままアレイに書き込みを行おうとすると、デバイスはコマンドを認識しますが、書き込みサイクルは発生せず、データは書き込まれず、デバイスは新しいコマンドをすぐに受け入る状態になります。
WPピンをVCCに接続すると、アレイ全体(00000-1FFFF)を書き込み保護できます。VSSに接続すると書き込み保護は無効になります。WPピンは、すべての書き込みコマンドのストップビットでサンプリングされます(図1-1)。ストップビットの後にWPピンを切り替えても、書き込みサイクルの実行には影響しません。
注意:
ページ書き込み操作は、実際に書き込まれているバイト数に関係なく、1つの物理ページ内のバイトの書き込みに制限されています。物理ページ境界は、ページバッファサイズ(または「ページサイズ」)の整数倍のアドレスで始まり、[ページサイズ– 1]の整数倍のアドレスで終わります。ページ書き込みコマンドが物理ページ境界を越えて書き込みを試みると、データは期待どおりに次のページに書き込まれるのではなく、現在のページの先頭に回り込みます(以前にそこに格納されたデータを上書きします)。したがって、アプリケーションソフトウェアは、ページ境界を越えようとするページ書き込み操作を防ぐ必要があります。
デバイスは書き込みサイクル中に[Acknowledge]しないため、これを使用してサイクルがいつ完了したかを判断できます。(この機能は、バスのスループットを最大化するために使用できます。)書き込みコマンドの[Stop condition]がマスターから発行されると、デバイスは内部タイミングの書き込みサイクルを開始します。ACKポーリングはすぐに開始できます。これには、マスターが[Start condition]を送信し、続いて書き込みコマンドの制御バイトを送信することが含まれます(R / W = 0)。デバイスがまだ書き込みサイクルでビジー状態の場合、ACKは返されません。ACKが返されない場合は、開始ビットと制御バイトを再送信する必要があります。サイクルが完了すると、デバイスはACKを返し、マスターは次の読み出しまたは書き込みコマンドを続行できます。フロー図については、図7-1を参照してください。
注:ポーリングに使用する制御バイトは、直前の書き込みに使用した制御バイトと同一(メモリーブロック)のものを使用する必要があります。
読み出し操作は、制御バイトのR / Wビットが1に設定されていることを除いて、書き込み操作と同じ方法で開始されます。読み出し操作には、現在のアドレス読み出し、ランダム読み出し、シーケンシャル読み出しの3つの基本タイプがあります。
24XX1025には、最後にアクセスしたワードのアドレスを保持するアドレスカウンターがあり、内部的に1ずつ増加します。したがって、前の読み出しアクセスがアドレスn(nは任意の有効なアドレス)であった場合、次の現在のアドレス読み出し操作はアドレスn + 1からデータにアクセスします。
R / Wビットが1に設定された制御バイトを受信すると、24XX1025は[Acknowledge]を発行し、8ビットのデータワードを送信します。マスターは転送の[Acknowledge]を発行せずに、[Stop condition]を生成し、24XX1025は送信を中止します(図8-1)。
ランダム読み出し操作により、マスターは任意のメモリ位置にランダムにアクセスできます。このタイプの読み出し操作を実行するには、まずワードアドレスを設定する必要があります。これは、書き込み操作の一部としてワードアドレスを24XX1025に送信することによって行われます(R / Wビットが0に設定されています)。ワードアドレスが送信された後、マスターは[Acknowledge]に続いて[Start condition]を生成します。これにより書き込み操作が終了しますが、内部アドレスポインターが設定される前ではありません。次に、マスターは制御バイトを再度発行しますが、R / Wビットは1に設定されています。次に24XX1025は[Acknowledge]を発行し、8ビットのデータワードを送信します。マスターは転送を確認しませんが、24XX1025が送信を中止する[Stop condition]を生成します(図8-2)。ランダムな読み出しコマンドの後、
24XX1025が最初のデータバイトを送信した後、マスターが[Acknowledge]を発行することを除いて、連続読み出しはランダム読み出しと同じ方法で開始されます。この[Acknowledge]は、24XX1025に次のアドレス指定された8ビットワードを送信するように指示します(図8-3)。マスターに送信された最後のバイトに続いて、マスターは[Acknowledge]を生成しませんが、[Stop condition]を生成します。連続読み出しを提供するために、24XX1025には、各操作の完了時に1ずつ増加する内部アドレスポインターが含まれています。このアドレスポインタにより、1回の操作でメモリの半分の内容をシリアルに読み取ることができます。シーケンシャルリードアドレスの境界は、0000h〜FFFFhおよび10000h〜1FFFFhです。マスターがアレイアドレス1FFFFから受信したバイトを確認すると、内部アドレスポインターはアドレスFFFFからアドレス0000に自動的にロールオーバーします。マスターがアレイアドレス1FFFFhから受信したバイトを確認すると、内部アドレスカウンターはアドレス1FFFFhからアドレス10000hに自動的にロールオーバーします。
PICkit 2 を図のように接続すれば、hex または bin ファイルの内容を、EEPROM に書き込むことが可能です。
EEPROM Adress 0x10 から連続する 8 byteにデータを書き込み、その後、データを読み出してLEDに表示する。
<回路図>
setumei
<プログラム main.c>
// EEPROM Adress 0x10 から連続する 8 byteにデータを書き込み // その後、データを読み出してLEDに表示する。 // // 1)Define I/O PORT // SDA:PORT B4 SCL:PORT B6 LEDs:PORTC C0-C3 // 2)OSC // 48MHz (内部クロック) // Language: MPLABX XC8 // Target: PIC16F1459 // Copyright (c) 2020 iwamoto All Rights Reserved //********************************************************* #include <xc.h> #include "I2C_EEPROM.h" #define _XTAL_FREQ 48000000 // LED on/off macro ------------------------------------------------ #define FlashLEDs() LATC=0xF;__delay_ms(100);LATC=0;__delay_ms(100) //************* Config *********************************** #pragma config FOSC = INTOSC, WDTE = OFF, PWRTE = OFF, MCLRE = OFF, CP = OFF #pragma config BOREN = ON, CLKOUTEN = OFF, IESO = OFF, FCMEN = OFF #pragma config WRT = OFF, CPUDIV = NOCLKDIV, USBLSCLK = 48MHz, PLLMULT = 3x #pragma config PLLEN = ENABLED, STVREN = ON, BORV = LO, LPBOR = OFF, LVP = OFF void outLEDs(char* data); // 配列のデータを1秒間隔でLEDに出力する // ********** Main **************************************** void main(void){ unsigned long Address = 0x10; char block; char W_data[]={8,4,2,1}; char R_data[4]; OSCCON = 0b11111100; // 内部クロック48Mhz TRISC = 0xF0; // LEDs output i2c_MasterInit(400000); // I2C初期化 400KHz FlashLEDs(); FlashLEDs(); // 開始合図 4灯点滅 2回 // ============= Byte Write ============================== Address = 0x10; EEPROM_WriteByte(Address++, 0x1); EEPROM_WriteByte(Address++, 0x2); EEPROM_WriteByte(Address++, 0x4); EEPROM_WriteByte(Address++, 0x8); // ============= Random Read ============================= Address = 0x10; R_data[0] = EEPROM_ReadRandom(Address++); R_data[1] = EEPROM_ReadRandom(Address++); R_data[2] = EEPROM_ReadRandom(Address++); R_data[3] = EEPROM_ReadRandom(Address++); outLEDs(R_data); FlashLEDs(); FlashLEDs(); // ============= Page Write =============================== Address = 0x14; EEPROM_WritePage(Address, W_data, 4); // ============= Sequential Read ========================= Address = 0x14; EEPROM_ReadSequential(Address, R_data, 4); outLEDs(R_data); FlashLEDs(); FlashLEDs(); // ============= Current Read ============================ Address = 0x10; block = EEPROM_AddressSet(Address); for (char i=0;i<8;i++){ LATC = EEPROM_ReadCurrent(block); __delay_ms(1000); } FlashLEDs(); FlashLEDs(); // 終了合図 4灯点滅 4回 FlashLEDs(); FlashLEDs(); while(1); } // 配列のデータを1秒間隔でLEDに出力する void outLEDs(char* data){ for (char i=0;i<4;i++){ LATC = data[i]; __delay_ms(1000); } }
<プログラム "I2C_EEPROM.h"
// File : I2C_EEPROM.h // I2C ports // RB4 = SDA // RB6 = SCL // -------------- I2C関連定義 ---------------------------- // 各シーケンスの終了を待って復帰 // I2C特殊 condition #define i2c_Idle() while((SSPCON2&0x1F)|(SSPSTATbits.R_nW)) #define i2c_Start() SSPCON2bits.SEN=1;while(SSPCON2bits.SEN) #define i2c_Stop() SSPCON2bits.PEN=1;while(SSPCON2bits.PEN) #define i2c_reStart() SSPCON2bits.RSEN=1;while(SSPCON2bits.RSEN) #define i2c_ACK() SSPCON2bits.ACKDT=0;SSPCON2bits.ACKEN=1;while(SSPCON2bits.ACKEN) #define i2c_NACK() SSPCON2bits.ACKDT=1;SSPCON2bits.ACKEN=1;while(SSPCON2bits.ACKEN) // -------------- プロトタイプ -------------------------- void i2c_MasterInit(const unsigned long baud); char i2c_Write(char data); char i2c_Read( void ); char EEPROM_AddressSet(unsigned long add); char EEPROM_ReadCurrent(char bk); char EEPROM_ReadRandom(unsigned long add); void EEPROM_ReadSequential(unsigned long add, char* data, unsigned int len); void EEPROM_WriteByte(unsigned long add, char data); void EEPROM_WritePage(unsigned long add, char* data, char len);
<プログラム I2C_EEPROM.c>
// File : I2C_EEPROM.c #include <xc.h> #include "I2C_EEPROM.h" #define _XTAL_FREQ 48000000 #define Slave_Add_R 0xA1 #define Slave_Add_W 0xA0 //--------------- I2C Routines ------------------- // Target PIC16F1459 void i2c_MasterInit(const unsigned long baud){ ANSB4 = 0; TRISB4 = 1; // SDA TRIS TRISB6 = 1; // SCL TRIS SSP1CON1 = 0b00101000; SSP1CON2 = 0; SSP1ADD = (_XTAL_FREQ/(4*baud))-1; // SSP1ADD = 0x77; SSP1STAT = 0; } /******************************************************** * i2c Library Master Mode Only *********************************************************/ char i2c_Write(char data){ SSPBUF = data; // データセット PIR1bits.SSP1IF = 0; // 終了フラグクリア while(!PIR1bits.SSP1IF); // 送信終了待ち return SSPCON2bits.ACKSTAT; // ACKなら「0」で復帰 } // NACKは「1」で復帰 char i2c_Read( void ){ SSPCON2bits.RCEN = 1; // データ受信を指示 while ( !SSPSTATbits.BF ); // 8ビット受信の完了を待つ return SSPBUF; // 受信データで復帰 } /************************************************************** * EEPROM に、1バイトを書き込む **************************************************************/ void EEPROM_WriteByte(unsigned long add, char data){ char bk = (add > 0xFFFF); // メモリブロックの取得 i2c_Idle(); // busアイドルの確認 i2c_Start(); // Start bit // MSSPが書き込み中か確認 while(i2c_Write(Slave_Add_W + bk*8)){ // 書き込み中なら i2c_reStart(); // 再スタートし再確認 } i2c_Write(add >> 8); // アドレス送信 i2c_Write((char)add); // アドレス送信 i2c_Write(data); // データ送信 i2c_Stop(); // Stop bit } /************************************************************** * EEPROM に、配列データを指定の長さ(len) 書き込む * 書き込み時間 5 ms 待ってから復帰する **************************************************************/ void EEPROM_WritePage(unsigned long add, char* data, char len){ char bk = (add > 0xFFFF); // メモリブロックの取得 i2c_Idle(); // busアイドルの確認 i2c_Start(); // Start bit while(i2c_Write(Slave_Add_W + bk*8)){ // 書き込み中なら i2c_reStart(); // 再スタートし再確認 } i2c_Write(add >> 8); // アドレス送信 i2c_Write((char)add); // アドレス送信 for(unsigned int i=0; i<len; i++){ // len回繰り返し i2c_Write(data[i]); // データ送信 } i2c_Stop(); // Stop bit } //----- Read Operations ----- /************************************************************** * EEPROM 内部アドレスポインタをセットする **************************************************************/ char EEPROM_AddressSet(unsigned long add){ char bk = (add > 0xFFFF); // メモリブロックの取得 i2c_Idle(); // busアイドルの確認 i2c_Start(); // Start bit while(i2c_Write(Slave_Add_W + bk*8)){ // 書き込み中なら i2c_reStart(); // 再スタートし再確認 } i2c_Write(add >> 8); // アドレス送信 i2c_Write((char)add); // アドレス送信 i2c_Stop(); // Stop bit return bk; // メモリブロック番号を返す } /************************************************************** * EEPROM 内部アドレスポインタの示すデータを読み出す * 読み出し後にアドレスポインタを +1 する **************************************************************/ char EEPROM_ReadCurrent(char bk){ char Data; i2c_Idle(); // busアイドルの確認 i2c_Start(); // Start bit i2c_Write(Slave_Add_R + bk*8); // 制御コード送信 Data = i2c_Read(); // データ受信 i2c_NACK(); // NACK送信 i2c_Stop(); // Stop bit return Data; } /************************************************************** * EEPROM 指定アドレスのデータを1バイト読み出す * 読み出し後にアドレスポインタを +1 する **************************************************************/ char EEPROM_ReadRandom(unsigned long add){ char Data; char bk = (add > 0xFFFF); // メモリブロックの取得 i2c_Idle(); // busアイドルの確認 i2c_Start(); // Start bit while(i2c_Write(Slave_Add_W + bk*8)){ // 書き込み中なら i2c_reStart(); // 再スタートし再確認 } i2c_Write(add >> 8); // アドレス送信 i2c_Write((char)add); // アドレス送信 i2c_reStart(); // Start bit i2c_Write(Slave_Add_R + bk*8); // 制御コード送信 Data = i2c_Read(); // データ受信 i2c_NACK(); // NACK送信 i2c_Stop(); // Stop bit return Data; } /************************************************************** * EEPROM 指定アドレスから * len バイトのデータを読み出し配列に保存する **************************************************************/ void EEPROM_ReadSequential(unsigned long add, char* data, unsigned int len){ char bk = (add > 0xFFFF); // メモリブロックの取得 i2c_Idle(); // busアイドルの確認 i2c_Start(); // Start bit while(i2c_Write(Slave_Add_W + bk*8)){ // 書き込み中なら i2c_reStart(); // 再スタートし再確認 } i2c_Write(add >> 8); // アドレス送信 i2c_Write((char)add); // アドレス送信 i2c_reStart(); // Start bit i2c_Write(Slave_Add_R + bk*8); // 制御コード送信 for(unsigned int i=0; i<len-1; i++){ // len-1 回繰り返し data[i] = i2c_Read(); // データ受信 i2c_ACK(); // ACK送信 } data[len-1] = i2c_Read(); // データ受信 i2c_NACK(); // NACK送信 i2c_Stop(); // Stop bit }