MSP430F2013 - EEPROM

提供: MochiuWiki : SUSE, EC, PCB

概要

EEPROM (Electrically Erasable Programmable Read-Only Memory) は、電気的に消去、書き込み可能な不揮発性メモリの1種である。

EEPROMは、マイコンのシステムで、不揮発性のデータ保存が必要な場合に広く使用されている。
フラッシュメモリと比較して書き換え回数が多く、バイト単位のアクセスが可能な点が特徴である。

ただし、書き換え速度が遅く、大容量のデータ保存には向かない。
また、書き換え回数にも制限があるため、頻繁に更新されるデータの保存には適していない。

したがって、用途に応じて、EEPROM、フラッシュメモリ、SRAM等の他のメモリデバイスを使い分ける必要がある。
マイコンの内蔵メモリでデータ保存が可能な場合は、外付けのEEPROMを使用しないこともある。

EEPROMの特徴
項目 特徴 説明
データ保持 不揮発性 電源を切ってもデータを保持できる。
書き込み方式 書き換え可能 データの消去と書き込みを電気的に行うことができる。
アクセス単位 バイト単位アクセス バイト単位でデータの読み書きが可能である。
耐久性 書き換え回数制限あり 一般的に、100万回程度の書き換えが可能である。
動作速度 低速 フラッシュメモリ等と比較して、読み書きの速度が遅い。
通信方式 シリアル通信 I2CやSPI等のシリアル通信インターフェースを使用して、マイクロコントローラと通信する。
記憶容量 小容量 数Kbit〜数Mbitまでの容量のデバイスが存在する。
主な用途 設定・データ保存向け 設定情報や較正データの保存、データロガー、小容量のデータ保存等に使用される。


EEPROMは、マイコンのシステムにおいて、小容量の不揮発性データ保存が必要な場合に重要な役割を果たすデバイスである。


EEPROMの種類

一般的に、外付けのEEPROMとして使用されているデバイスには、以下に示すようなものがある。

以下に示すEEPROMは、MSP430F2013マイコンのI2CまたはSPIインターフェースに直接接続して使用することができる。
容量や速度、インターフェースの種類などの要件に応じて選択する。

特に、24LC256は、比較的大容量でI2Cインターフェースを備えているため、MSP430F2013マイコンの組み合わせで広く使用されている人気の高い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グレードの信頼性



MSP430F2013とEEPROMの接続

MSP430F2013マイコンは、USI (Universal Serial Interface) モジュールを使用してI2CまたはSPI通信を行うことができる。

I2C接続

MSP430F2013のUSIモジュールをI2Cモードで使用する場合、以下のピンを使用する。

  • P1.7 - SDA (I2Cデータライン)
  • P1.6 - SCL (I2Cクロックライン)


I2C通信では、SDAとSCLの両方のラインに外部プルアップ抵抗 (通常4.7[kΩ]~10[kΩ]) が必要である。
複数のデバイスをI2Cバスに接続する場合は、それぞれのデバイスに異なるアドレスを設定する。

USIモジュールのピン機能を有効化するには、USICTL0レジスタでUSIPE7とUSIPE6ビットをセットする。
また、USIPE5ビットはSPI等と共用している場合があるため、セットしてもよい。

SPI接続

MSP430F2013のUSIモジュールをSPIモードで使用する場合、以下のピンを使用する。

  • P1.6 - SDO/SIMO (マスタ出力、スレーブ入力)
  • P1.7 - SDI/SOMI (マスタ入力、スレーブ出力)
  • P1.5 - SCLK (SPIクロック)
  • P1.x - CS (チップセレクト、GPIO制御、任意のポート)


SPI通信では、チップセレクト (CS) 信号は通常のGPIOピンを使用して制御する。
複数のSPIデバイスを接続する場合は、それぞれに異なるCSピンを割り当てる。

USIモジュールのピン機能を有効化するには、USICTL0レジスタでUSIPE7、USIPE6、USIPE5ビットをセットする。


USI (Universal Serial Interface)

MSP430F2013のUSI (Universal Serial Interface) をSPIマスタとして使用する。

SPIモード

SPIには4種類の動作モードが存在しており、以下に示す2つのパラメータで定義される。

  • CPOL (Clock POLarity)
    クロックのアイドル状態
  • CPHA (Clock PHAse)
    データのサンプリングタイミング


SPI Mode CPOL CPHA クロック待機状態 データ取得エッジ
Mode 0 0 0 Low 立上り
Mode 1 0 1 Low 立下り
Mode 2 1 0 High 立下り
Mode 3 1 1 High 立上り


USICKPH / USICKPL と SPIモードの対応

MSP430F2013のUSIでは、SPIモードは以下に示す2ビットで決定される。

USIビット 意味
USICKPL クロック極性 (CPOL)
USICKPH クロック位相 (CPHA)


対応表
SPIモード USICKPL USICKPH
モード 0 0 0
モード 1 0 1
モード 2 1 0
モード 3 1 1


USIOE (USI Output Enable)

USIOE (USI Output Enable)は、USIがピンを出力として駆動するかどうかを制御するビットである。

SPIマスタ動作時では、以下に示す信号をMSP430F2013側が生成する必要がある。
このため、SPIマスタでは USIOE = 1 が必須となる。

  • SCLK (クロック)
    出力
  • MOSI
    出力
  • MISO
    入力


仮に、USIOE = 0 の場合、以下に示すようにSPI通信は成立しない。

  • SCLKが出力されない。
  • MOSIがハイインピーダンス (Hi-Z) となる。


MOSI / MISOが方向切替されない理由

SPI通信はフルデュプレックス通信であり、データ線の方向は固定である。

USIが内部的に入出力方向を固定管理するため、P1DIRレジスタを直接操作する必要はない。
これは、1本の双方向データ線を使うI2C通信との大きな違いである。

信号 方向
MOSI マスター --> スレーブ
MISO スレーブ --> マスター



サンプルコード

24LC256 (256Kbit I2C EEPROM)

以下の例では、I2C通信を使用してEEPROMとの通信を行っている。
I2C通信を初期化した後、i2c_write_byte関数を使用してEEPROMにデータを書き込み、i2c_read_byte関数を使用して書き込んだデータを読み出している。

  1. usi_i2c_init関数でI2Cの初期化を行う。
    ピンの設定、I2Cの設定、クロック周波数の設定等を行う。

    MSP430F2013マイコンのP1.7をSDA、P1.5をSCLに指定している。

  2. i2c_write_byte関数を使用して、指定したアドレスにデータを書き込む。
    スタートコンディション、アドレスの送信、データの送信、ストップコンディションの順に処理を行う。

  3. i2c_read_byte関数を使用して、指定したアドレスからデータを読み出す。
    スタートコンディション、アドレスの送信、再スタートコンディション、データの受信、ストップコンディションの順に処理を行う。


実際に動作させる場合は、回路の接続や電源の供給等にも注意が必要である。
特に、I2C通信では、SDAとSCLのラインに2.2[kΩ]~10[kΩ]のプルアップ抵抗を接続する必要がある。

MSP430F2013では、USIのI2C機能はPort 1の以下に示すピンに固定されている。

  • P1.6
    USI SCL
  • P1.7
    USI SDA


下図に、MSP430F2013と24LC256のシーケンス図を示す。


 #include <msp430f2013.h>
 
 // 24LC256のI2Cアドレス
 // 24LC256のA0, A1, A2ピンがGNDに接続されている場合
 #define EEPROM_ADDRESS 0x50
 
 void usi_i2c_init();
 void i2c_start();
 void i2c_stop();
 void i2c_write_byte_data(unsigned char data);
 unsigned char i2c_read_byte_ack();
 unsigned char i2c_read_byte_nack();
 void eeprom_write_byte(unsigned int address, unsigned char data);
 unsigned char eeprom_read_byte(unsigned int address);
 
 int main(void)
 {
    WDTCTL = WDTPW + WDTHOLD;       // ウォッチドッグタイマを停止
 
    // DCOクロック設定 (1MHz)
    BCSCTL1 = CALBC1_1MHZ;
    DCOCTL = CALDCO_1MHZ;
 
    usi_i2c_init();                 // I2Cの初期化
 
    unsigned char data = 0xAA;      // 書き込むデータ
    unsigned int address = 0x0010;  // EEPROMのメモリアドレス
 
    eeprom_write_byte(address, data);  // EEPROMにデータを書き込み
 
    __delay_cycles(50000);          // 書き込み完了待機 (約50ms)
 
    unsigned char read_data = eeprom_read_byte(address);  // EEPROMからデータを読み出し
 
    while(1);
 }
 
 void usi_i2c_init()
 {
    USICTL0 = USIPE7 + USIPE6 + USIPE5 + USIMST + USISWRST;  // ポート有効、マスタ、SW Reset
                                                             // USIPE7 : P1.7をUSI機能 (SDA) として有効
                                                             // USIPE6 : P1.6をUSI機能 (SCL) として有効
                                                             // USIPE5 : I2Cでは通常未使用であるが、SPI等との共用ビットのため含まれていることがある
                                                             // USIMST : マスターモード
                                                             // USISWRST : USIソフトウェアリセット
    USICTL1 = USII2C + USIIE;                                // I2Cモード、割り込み有効
    USICKCTL = USIDIV_7 + USISSEL_2 + USICKPL;               // SMCLK/128、クロック極性
    USICNT |= USIIFGCC;                                      // USICNTで自動クリア無効
    USICTL0 &= ~USISWRST;                                    // SW Resetを解除
    USICTL1 &= ~USIIFG;                                      // 割り込みフラグクリア
 }
 
 void i2c_start()
 {
    USISRL = 0x00;                  // SDAをLowに
    USICTL0 |= USIGE + USIOE;       // 出力有効
    USICTL0 &= ~USIGE;
 
    USISRL = 0xFF;                  // SDAをHighに
    USICNT = 1;                     // SCLを1クロック (Start Condition)
    while(!(USICTL1 & USIIFG));     // 完了待ち
    USICTL0 |= USIGE;               // 透過ラッチ有効
    USISRL = 0xFF;
    USICTL0 &= ~USIGE;
 }
 
 void i2c_stop()
 {
    USICTL0 |= USIOE;               // 出力有効
    USISRL = 0x00;
    USICNT = 1;                     // SDAをLowに
    while(!(USICTL1 & USIIFG));
 
    USISRL = 0xFF;
    USICTL0 |= USIGE;               // 透過ラッチ有効
    USICTL0 &= ~(USIGE + USIOE);    // SDAを解放
    USICTL1 &= ~USIIFG;             // フラグクリア
 }
 
 void i2c_write_byte_data(unsigned char data)
 {
    USICTL0 |= USIOE;               // 出力有効
    USISRL = data;                  // データをシフトレジスタにセット
    USICNT = 8;                     // 8ビット送信
    while(!(USICTL1 & USIIFG));     // 送信完了待ち
 
    // ACK/NACK受信
    USICTL0 &= ~USIOE;              // 受信モードに
    USICNT = 1;                     // 1ビット受信 (ACK/NACK)
    while(!(USICTL1 & USIIFG));
    USICTL1 &= ~USIIFG;
 }
 
 unsigned char i2c_read_byte_ack()
 {
    USICTL0 &= ~USIOE;              // 受信モードに
    USICNT = 8;                     // 8ビット受信
    while(!(USICTL1 & USIIFG));
    unsigned char data = USISRL;
 
    // ACK送信
    USICTL0 |= USIOE;               // 送信モードに
    USISRL = 0x00;                  // ACK (Low)
    USICNT = 1;
    while(!(USICTL1 & USIIFG));
    USICTL1 &= ~USIIFG;
 
    return data;
 }
 
 unsigned char i2c_read_byte_nack()
 {
    USICTL0 &= ~USIOE;              // 受信モードに
    USICNT = 8;                     // 8ビット受信
    while(!(USICTL1 & USIIFG));
    unsigned char data = USISRL;
 
    // NACK送信
    USICTL0 |= USIOE;               // 送信モードに
    USISRL = 0xFF;                  // NACK (High)
    USICNT = 1;
    while(!(USICTL1 & USIIFG));
    USICTL1 &= ~USIIFG;
 
    return data;
 }
 
 void eeprom_write_byte(unsigned int address, unsigned char data)
 {
    i2c_start();                                    // スタートコンディション
    i2c_write_byte_data((EEPROM_ADDRESS << 1) | 0); // アドレス + Write
    i2c_write_byte_data((address >> 8) & 0xFF);     // アドレス上位
    i2c_write_byte_data(address & 0xFF);            // アドレス下位
    i2c_write_byte_data(data);                      // データ
    i2c_stop();                                     // ストップコンディション
 }
 
 unsigned char eeprom_read_byte(unsigned int address)
 {
    unsigned char data;
 
    i2c_start();                                    // スタートコンディション
    i2c_write_byte_data((EEPROM_ADDRESS << 1) | 0); // アドレス + Write
    i2c_write_byte_data((address >> 8) & 0xFF);     // アドレス上位
    i2c_write_byte_data(address & 0xFF);            // アドレス下位
 
    i2c_start();                                    // リピーテッドスタート
    i2c_write_byte_data((EEPROM_ADDRESS << 1) | 1); // アドレス + Read
    data = i2c_read_byte_nack();                    // データ受信 + NACK
    i2c_stop();                                     // ストップコンディション
 
    return data;
 }


25LC640A (64Kbit SPI EEPROM)

25LC640Aが対応するSPIモードは、SPIモード 0 / 3 である。
25LC640Aでは、SPIモード 1 / 2 は仕様外のため注意すること。

一般的で扱いやすいモードは、SPIモード 0である。
ただし、ノイズ耐性を考慮する場合は、SPIモード 3も選択可能である。

25LC640AのSPIモード対応表
SPIモード 対応可否
Mode 0
Mode 1 -
Mode 2 -
Mode 3


以下の例では、SPI通信を使用してEEPROMとの通信を行っている。
SPIの初期化後、eeprom_write_byte関数を使用してEEPROMにデータを書き込み、eeprom_read_byte関数を使用して書き込んだデータを読み出している。

  1. usi_spi_init関数でSPIの初期化を行う。
    ピンの設定、SPIの設定、クロック周波数の設定等を行う。

    MSP430F2013マイコンのP1.6をSDO、P1.7をSDI、P1.5をSCLKに指定している。

  2. eeprom_write_byte関数を使用して、指定したアドレスにデータを書き込む。
    WRENコマンドで書き込み有効化して、WRITEコマンドでアドレスとデータを送信する。

  3. eeprom_read_byte関数を使用して、指定したアドレスからデータを読み出す。
    READコマンドでアドレスを送信して、データを受信する。


実際に動作させる場合は、回路の接続や電源の供給等にも注意が必要である。
特に、25LC640AのCS (チップセレクト) ピンは、適切なポートピンに接続して、ソースコード内で設定する必要がある。

下図に、MSP430F2013と25LC640Aのシーケンス図を示す。


 #include <msp430f2013.h>
 
 // CSピンの設定 (例: P1.0)
 #define CS_PIN BIT0
 #define CS_LOW()    P1OUT &= ~CS_PIN
 #define CS_HIGH()   P1OUT |= 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 usi_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クロック設定 (1MHz)
    BCSCTL1 = CALBC1_1MHZ;
    DCOCTL = CALDCO_1MHZ;
 
    P1DIR |= CS_PIN;                // CSピンを出力に設定
    CS_HIGH();                      // CSピンをハイに設定
 
    usi_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 usi_spi_init()
 {
    // USIをSPIマスターモードで初期化
    USICTL0 = USIPE7 + USIPE6 + USIPE5 + USIMST + USIOE + USISWRST; // ピン有効、マスタ、出力有効
 
    // SPIモード 0を使用する場合
    USICTL1 = 0;                      // クロック位相 : データはSCLK立上りでキャプチャ、立下りで変化
    USICKCTL = USIDIV_1 + USISSEL_2;  // SMCLK / 2を使用 (約500[kHz])
 
    // SPIモード 3を使用する場合
    // USICTL1 = USICKPH;                         // クロック位相 : データはSCLK立下りでキャプチャ、立下りで変化
    // USICKCTL = USIDIV_1 + USISSEL_2 + USICKPL; // Mode 1,1用にクロック極性を反転
 
    USICNT |= USIIFGCC;               // USICNTで自動クリア無効
    USICTL0 &= ~USISWRST;             // SW Resetを解除
 }
 
 unsigned char spi_transfer(unsigned char data)
 {
    USISRL = data;                  // 送信データをシフトレジスタにセット
    USICNT = 8;                     // 8ビット送信/受信
    while(!(USICTL1 & USIIFG));     // 転送完了待ち
    USICTL1 &= ~USIIFG;             // フラグクリア
    return USISRL;                  // 受信データを返す
 }
 
 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に接続されている場合) だが、実装により異なる場合がある。


注意事項

MSP430F2013マイコンを使用してEEPROMと通信する場合には、以下に示す事柄に注意する。

共通

  • 電源電圧
    EEPROMの動作電圧範囲を確認し、MSP430F2013の電源電圧と一致していることを確認する。
  • デカップリングコンデンサ
    EEPROMの電源ピンの近くに、0.1[μF]のデカップリングコンデンサを配置する。
  • 配線長
    I2CおよびSPIの信号線は、できるだけ短く、かつノイズの影響を受けにくいように配線する。
  • エラー処理
    実際のアプリケーションでは、通信エラーや書き込みエラーに対する適切なエラー処理を実装する必要がある。
  • メモリ容量
    MSP430F2013は2KB Flashと128B RAMという限られたメモリ容量のため、コードサイズの最適化が重要である。


I2C通信

  • プルアップ抵抗
    I2CのSDAとSCLのラインには、必ず外部プルアップ抵抗 (4.7[kΩ]~10[kΩ]) を接続する必要がある。
  • クロック周波数
    I2C通信のクロック周波数は、標準モードで100[kHz]、高速モードで400[kHz]までサポートされている。
  • 書き込み完了時間
    EEPROMへの書き込み後、内部書き込みサイクルが完了するまで約5[ms]の待機時間が必要である。
  • アドレッシング
    16ビットアドレスのEEPROMでは、アドレスを2バイトで送信する必要がある。
  • USIのI2Cスレーブモード制約 (Errata USI2, USI3, USI4)
    MSP430F2013のUSIモジュールには、I2Cスレーブモードに関するいくつかの既知の問題がある。
    I2Cスレーブモードを使用する場合は、20[kbps]以上の通信速度を推奨。
    本サンプルコードでは、マスターモードのみを使用しているため、この問題の影響は受けない。


SPI通信

  • チップセレクト制御
    SPI通信では、通信前にCS信号をLOWに、通信後にHIGHにする必要がある。
  • クロック極性と位相
    SPIのクロック極性と位相は、EEPROMのデータシートに従って設定する必要がある。
  • 書き込み有効化
    EEPROMへの書き込み前に、必ずWRENコマンドで書き込みを有効化する必要がある。
  • ステータス確認
    書き込み操作後、ステータスレジスタを読み取り、WIPビットが0になるまで待機する必要がある。
  • 初回転送時の注意 (Errata USI5)
    USICKPHビットをセットした状態でUSIをSPIマスターモードで初期化すると、リセット後の最初のデータ転送時に1クロック余分に生成される。
    回避策として、初期化後にダミー転送を1回実行するか、USICKPHビットをクリアして使用する。


MSP430F2013固有の制約

  • USIモジュールの制限
    USIは、MSP430F149のUSARTモジュールと比較して機能が制限されている。
    I2CおよびSPIの基本的な通信機能のみをサポートする。
    ハードウェアによる自動アドレス認識やFIFOバッファは搭載されていない。
  • メモリ容量の制限
    Flash: 2KB、RAM: 128Bと非常に限られているため、大規模なバッファやデータ構造は使用できない。
    コードサイズの最適化とメモリ使用量の削減が重要である。
  • クロック設定
    DCOキャリブレーションデータ (CALBC1_1MHZ、CALDCO_1MHZ等) を使用して、正確なクロック周波数を設定する。
    キャリブレーションデータはInfo Memoryセグメントに格納されている。