「MSP430G2553 - FRAM (FeRAM)」の版間の差分

提供:MochiuWiki : SUSE, EC, PCB
ナビゲーションに移動 検索に移動
64行目: 64行目:
     WDTCTL = WDTPW | WDTHOLD;  // ウォッチドッグタイマを停止
     WDTCTL = WDTPW | WDTHOLD;  // ウォッチドッグタイマを停止
   
   
     initI2C(); // I2Cの初期化
     initI2C();                 // I2Cの初期化
   
   
     // 書き込むデータ
     // 書き込むデータ
72行目: 72行目:
     unsigned char readData[4];
     unsigned char readData[4];
   
   
     // FRAMにデータを書き込む (アドレス0x00から)
     // FRAMに4バイトのデータを書き込む (アドレス0x00から)
     I2C_write(0x00, writeData, 4);
     I2C_write(0x00, writeData, 4);
   
   
     // 少し待機
     // 100[mS]待機
     __delay_cycles(100000);
     __delay_cycles(100000);
   
   
     // FRAMからデータを読み出す (アドレス0x00から)
     // FRAMから4バイトのデータを読み出す (アドレス0x00から)
     I2C_read(0x00, readData, 4);
     I2C_read(0x00, readData, 4);
   
   
86行目: 86行目:
  void initI2C(void)
  void initI2C(void)
  {
  {
     P1SEL |= BIT6 + BIT7; // P1.6 = SCL, P1.7 = SDA
     P1SEL   |= BIT6 + BIT7;                 // P1.6 = SCL, P1.7 = SDA
     P1SEL2 |= BIT6 + BIT7;
     P1SEL2   |= BIT6 + BIT7;
     UCB0CTL1 |= UCSWRST; // UCB0をリセット状態に
     UCB0CTL1 |= UCSWRST;                     // UCB0をリセット状態に
     UCB0CTL0 = UCMST + UCMODE_3 + UCSYNC; // I2Cマスターモード
     UCB0CTL0 = UCMST + UCMODE_3 + UCSYNC;   // I2Cマスターモード
     UCB0CTL1 = UCSSEL_2 + UCSWRST; // SMCLKを選択
     UCB0CTL1 = UCSSEL_2 + UCSWRST;         // SMCLKを選択
     UCB0BR0 = 12; // fSCL = SMCLK/12 = 100kHz
     UCB0BR0   = 12;                         // fSCL = SMCLK / 12 = 100[kHz]
     UCB0BR1 = 0;
     UCB0BR1   = 0;
     UCB0I2CSA = FRAM_ADDR; // スレーブアドレスをセット
     UCB0I2CSA = FRAM_ADDR;                   // スレーブアドレスをセット
     UCB0CTL1 &= ~UCSWRST; // UCB0のリセットを解除
     UCB0CTL1 &= ~UCSWRST;                   // UCB0のリセットを解除
  }
  }
   
   
  void I2C_write(unsigned char addr, unsigned char *data, unsigned int len)
  void I2C_write(unsigned char addr, unsigned char *data, unsigned int len)
  {
  {
     while (UCB0CTL1 & UCTXSTP); // 前の通信が終了するまで待機
     while (UCB0CTL1 & UCTXSTP);   // 前の通信が終了するまで待機
     UCB0CTL1 |= UCTR + UCTXSTT;  // 送信モード、スタートコンディション
     UCB0CTL1 |= UCTR + UCTXSTT;  // 送信モード、スタートコンディション
     while (!(IFG2 & UCB0TXIFG));  // TXバッファが空になるまで待機
     while (!(IFG2 & UCB0TXIFG));  // TXバッファが空になるまで待機
     UCB0TXBUF = addr; // メモリアドレスを送信
     UCB0TXBUF = addr;           // メモリアドレスを送信
     while (!(IFG2 & UCB0TXIFG));  // TXバッファが空になるまで待機
     while (!(IFG2 & UCB0TXIFG));  // TXバッファが空になるまで待機
   
   
     while (len--) {
     while (len--) {
         UCB0TXBUF = *data++; // データを送信
         UCB0TXBUF = *data++;         // データを送信
         while (!(IFG2 & UCB0TXIFG));  // TXバッファが空になるまで待機
         while (!(IFG2 & UCB0TXIFG));  // TXバッファが空になるまで待機
     }
     }
   
   
     UCB0CTL1 |= UCTXSTP; // ストップコンディション
     UCB0CTL1 |= UCTXSTP;             // ストップコンディション
     while (UCB0CTL1 & UCTXSTP); // ストップコンディションが送信されるまで待機
     while (UCB0CTL1 & UCTXSTP);       // ストップコンディションが送信されるまで待機
  }
  }
   
   
  void I2C_read(unsigned char addr, unsigned char *data, unsigned int len)
  void I2C_read(unsigned char addr, unsigned char *data, unsigned int len)
  {
  {
     while (UCB0CTL1 & UCTXSTP); // 前の通信が終了するまで待機
     while (UCB0CTL1 & UCTXSTP);   // 前の通信が終了するまで待機
     UCB0CTL1 |= UCTR + UCTXSTT;  // 送信モード、スタートコンディション
     UCB0CTL1 |= UCTR + UCTXSTT;  // 送信モード、スタートコンディション
     while (!(IFG2 & UCB0TXIFG));  // TXバッファが空になるまで待機
     while (!(IFG2 & UCB0TXIFG));  // TXバッファが空になるまで待機
     UCB0TXBUF = addr; // メモリアドレスを送信
     UCB0TXBUF = addr;           // メモリアドレスを送信
     while (!(IFG2 & UCB0TXIFG));  // TXバッファが空になるまで待機
     while (!(IFG2 & UCB0TXIFG));  // TXバッファが空になるまで待機
   
   
     UCB0CTL1 &= ~UCTR; // 受信モードに切り替え
     UCB0CTL1 &= ~UCTR;           // 受信モードに切り替え
     UCB0CTL1 |= UCTXSTT; // リスタートコンディション
     UCB0CTL1 |= UCTXSTT;         // リスタートコンディション
     while (UCB0CTL1 & UCTXSTT); // スタートコンディションが送信されるまで待機
     while (UCB0CTL1 & UCTXSTT);   // スタートコンディションが送信されるまで待機
   
   
     while (len--) {
     while (len--) {
         while (!(IFG2 & UCB0RXIFG));  // RXバッファにデータが来るまで待機
         while (!(IFG2 & UCB0RXIFG));  // RXバッファにデータが来るまで待機
         *data++ = UCB0RXBUF; // データを読み出し
         *data++ = UCB0RXBUF;         // データを読み出し
         if (len == 0)
         if (len == 0)
             UCB0CTL1 |= UCTXSTP; // 最後のバイトを読み出す前にストップコンディションを送信
             UCB0CTL1 |= UCTXSTP;     // 最後のバイトを読み出す前にストップコンディションを送信
     }
     }
   
   
     while (UCB0CTL1 & UCTXSTP); // ストップコンディションが送信されるまで待機
     while (UCB0CTL1 & UCTXSTP);       // ストップコンディションが送信されるまで待機
  }
  }
  </syntaxhighlight>
  </syntaxhighlight>
147行目: 147行目:
*: FRAMへの連続的なアクセスを避けて、デバイスに「休憩」を与える。
*: FRAMへの連続的なアクセスを避けて、デバイスに「休憩」を与える。
<br>
<br>
ただし、実際の設計では、この長い遅延は必ずしも必要ではない。<bR>
ただし、実際の設計では、この長い遅延は必ずしも必要ではない。<br>
FRAMは、一般的に、マイクロ秒オーダーで書き込みを完了するため、実運用では以下のような方法を検討できる。<br>
FRAMは、一般的に、マイクロ秒オーダーで書き込みを完了するため、実運用では以下のような方法を検討できる。<br>
* 遅延時間の短縮
* 遅延時間の短縮

2024年6月30日 (日) 10:21時点における版

概要



FRAMの種類

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

MSP430G2553マイコンで使用できるFRAMについては、いくつかの選択肢がある。

  • Cypress (現Infineon)
    FM24シリーズ
    FM24CL04B, FM24CL16B, FM24CL64B
  • Fujitsu (現Lapis)
    MB85シリーズ
    MB85RC256V, MB85RC512T


これらのFRAMは、一般的に、I2CインターフェースでMSP430G2553マイコンに接続できる。
MSP430G2553マイコンはI2C通信をサポートしているため、これらのFRAMとの通信が可能である。

F-RAMを選択する時の主な考慮点を、以下に示す。

  • 容量
    必要なストレージ容量に応じて選択する。
  • 動作電圧
    MSP430G2553マイコンの動作電圧範囲と合致するもの。
  • 通信速度
    I2Cの速度に対応しているかどうか。
  • パッケージ
    基板設計に適したものかどうか。


具体的な製品を選択する場合は、データシートを確認して、MSP430G2553マイコンとの互換性を確認することが重要である。

FM24CL04B, FM24CL16B, FM24CL64B (I2C FRAM)

  • Microchip社製の不揮発性メモリ
  • I2Cインターフェースを使用
  • 32[KB] (256[Kbit]) の容量
  • 低消費電力で動作


MB85RC256V, MB85RC512T (I2C FRAM)

  • 富士通の不揮発性メモリ
  • I2Cインターフェースを使用
  • 8[KB] (64[Kbit]) の容量
  • 高速動作が可能



サンプルコード

FM24CL04B, FM24CL16B, FM24CL64B

以下の例では、MSP430G2553マイコンとFM24CL16BまたはFM24CL64B (FRAM) を使用してデータを読み書きしている。

  1. I2C通信を初期化する。
  2. FRAMのアドレス0x00から4バイトのデータを書き込む。
  3. 100[mS]待機する。
  4. FRAMのアドレス0x00から4バイトのデータを読み出す。


 #include <msp430g2553.h>
 
 #define FRAM_ADDR 0x50  // FRAMのI2Cアドレス
 
 void initI2C(void);
 void I2C_write(unsigned char addr, unsigned char *data, unsigned int len);
 void I2C_read(unsigned char addr, unsigned char *data, unsigned int len);
 
 int main(void)
 {
    WDTCTL = WDTPW | WDTHOLD;  // ウォッチドッグタイマを停止
 
    initI2C();                 // I2Cの初期化
 
    // 書き込むデータ
    unsigned char writeData[] = {0x12, 0x34, 0x56, 0x78};
 
    // 読み出し用バッファ
    unsigned char readData[4];
 
    // FRAMに4バイトのデータを書き込む (アドレス0x00から)
    I2C_write(0x00, writeData, 4);
 
    // 100[mS]待機
    __delay_cycles(100000);
 
    // FRAMから4バイトのデータを読み出す (アドレス0x00から)
    I2C_read(0x00, readData, 4);
 
    while(1);
 }
 
 void initI2C(void)
 {
    P1SEL    |= BIT6 + BIT7;                 // P1.6 = SCL, P1.7 = SDA
    P1SEL2   |= BIT6 + BIT7;
    UCB0CTL1 |= UCSWRST;                     // UCB0をリセット状態に
    UCB0CTL0  = UCMST + UCMODE_3 + UCSYNC;   // I2Cマスターモード
    UCB0CTL1  = UCSSEL_2 + UCSWRST;          // SMCLKを選択
    UCB0BR0   = 12;                          // fSCL = SMCLK / 12 = 100[kHz]
    UCB0BR1   = 0;
    UCB0I2CSA = FRAM_ADDR;                   // スレーブアドレスをセット
    UCB0CTL1 &= ~UCSWRST;                    // UCB0のリセットを解除
 }
 
 void I2C_write(unsigned char addr, unsigned char *data, unsigned int len)
 {
    while (UCB0CTL1 & UCTXSTP);   // 前の通信が終了するまで待機
    UCB0CTL1  |= UCTR + UCTXSTT;  // 送信モード、スタートコンディション
    while (!(IFG2 & UCB0TXIFG));  // TXバッファが空になるまで待機
    UCB0TXBUF  = addr;            // メモリアドレスを送信
    while (!(IFG2 & UCB0TXIFG));  // TXバッファが空になるまで待機
 
    while (len--) {
        UCB0TXBUF = *data++;          // データを送信
        while (!(IFG2 & UCB0TXIFG));  // TXバッファが空になるまで待機
    }
 
    UCB0CTL1 |= UCTXSTP;              // ストップコンディション
    while (UCB0CTL1 & UCTXSTP);       // ストップコンディションが送信されるまで待機
 }
 
 void I2C_read(unsigned char addr, unsigned char *data, unsigned int len)
 {
    while (UCB0CTL1 & UCTXSTP);   // 前の通信が終了するまで待機
    UCB0CTL1  |= UCTR + UCTXSTT;  // 送信モード、スタートコンディション
    while (!(IFG2 & UCB0TXIFG));  // TXバッファが空になるまで待機
    UCB0TXBUF  = addr;            // メモリアドレスを送信
    while (!(IFG2 & UCB0TXIFG));  // TXバッファが空になるまで待機
 
    UCB0CTL1 &= ~UCTR;            // 受信モードに切り替え
    UCB0CTL1 |= UCTXSTT;          // リスタートコンディション
    while (UCB0CTL1 & UCTXSTT);   // スタートコンディションが送信されるまで待機
 
    while (len--) {
        while (!(IFG2 & UCB0RXIFG));  // RXバッファにデータが来るまで待機
        *data++ = UCB0RXBUF;          // データを読み出し
        if (len == 0)
            UCB0CTL1 |= UCTXSTP;      // 最後のバイトを読み出す前にストップコンディションを送信
    }
 
    while (UCB0CTL1 & UCTXSTP);       // ストップコンディションが送信されるまで待機
 }


100[mS]の遅延を入れている理由を、以下に示す。

  • 書き込み完了の保証
    F-RAMは非常に高速であるが、書き込み操作が完全に終了するまでに短い時間が必要な場合がある。
  • デバッグや動作確認
    プログラムの動作を人間のタイムスケールで確認しやすくする。
  • 電気的な安定性
    書き込み後にシステムが電気的に安定するための時間を確保する。
  • 連続アクセスの回避
    FRAMへの連続的なアクセスを避けて、デバイスに「休憩」を与える。


ただし、実際の設計では、この長い遅延は必ずしも必要ではない。
FRAMは、一般的に、マイクロ秒オーダーで書き込みを完了するため、実運用では以下のような方法を検討できる。

  • 遅延時間の短縮
    例えば、1[mS]の遅延に短縮する。
  • ポーリングによる完了確認
    FRAMの状態レジスタを読み取り、書き込み完了を確認する。
  • 遅延の除去
    多くの場合、FRAMは遅延なしで連続アクセスが可能である。
  • 割り込みの使用
    I2C通信完了の割り込みを使用して、効率的に次の操作に移行する。


※注意

  • FRAMのI2Cアドレス (FRAM_ADDR) は、使用するデバイスによって異なる場合があるため、データシートで確認すること。
  • 実務で使用する場合は、エラー処理やタイムアウト処理を追加することを推奨する。
  • FRAMの容量に応じて、アドレス指定の方法を調整する必要がある。