アプリケーションノート 4112

MAXQ®プロセッサの不揮発性メモリサービスの活用

筆者: Ben Smith

要約: 不揮発性データストレージを必要とするアプリケーションでは、ほとんどの場合、外付けのシリアルEEPROMが使用されます。このアプリケーションノートでは、MAXQマイクロコントローラが元々備えているフラッシュメモリのみを使用して不揮発性データストレージを提供する方法について解説します。

はじめに

マイクロコントローラを必要とするほとんどのアプリケーションでは、設定を保存して電源がオフになった場合でも復元することができる、何らかの仕組みも必要になります。たとえばラジオの場合、電池交換時に放送局のプリセット内容が消えてしまうようでは、今日の市場で成功を望むことはできません。ユーザーは、お気に入りの放送局、温度のプリセット、好みの設定、その他の永続的情報が、次回の使用時に備えて保存されることを期待しています。

不揮発性データストレージに対するこうしたユーザーの期待に応えるため、設計者は伝統的にシリアルEEPROMを使用してきました。これらのEEPROMデバイスは小型で低コストであり、長い歴史があるため設計エンジニアは安心して使用することができます。しかし、コストに敏感な現在の市場では、安価なEEPROMデバイスを追加しただけで予算を超過する可能性があります。

多くのプロセッサは、プログラムコードの格納にフラッシュメモリを、データストレージにスタティックRAMを使用しています。フラッシュメモリの未使用部分を不揮発性データストレージに活用するというのは魅力的な考えですが、従来のハーバードアーキテクチャではこうした使用法が不可能でした。しかし、MAXQアーキテクチャはコード用とデータ用に独立した経路を備えたハーバードマシンです。MAXQデバイスは疑似フォンノイマンアーキテクチャを実装するハードウェアを内蔵しており、コードスペースに対するデータメモリとしてのアクセスを容易に行うことができます。この特別な柔軟性と、メモリ書込み/消去サービスを提供するMAXQのユーティリティ機能との組合せによって、読み書き可能な完全な不揮発性メモリサブシステムの基盤が与えられます。

フラッシュメモリについての基本的な考察

フラッシュメモリは、電気的に消去可能なメモリの一種です。一般的には、「ほぼ読取り専用」と考えられています。簡単に言うと、フラッシュメモリは書込み可能ですが、データの更新が頻繁に行われず、操作の大部分が読取り操作であるような用途が想定されています。ほとんどのフラッシュメモリデバイスは、書込みはワードレベルで行うことができますが、消去は一度に1ブロック全体でしか行うことができません。そのため、一般にこれらのメモリデバイスは変数の格納には適さず、決して変化しない定数データのテーブルにのみ適します。

フラッシュメモリには、NANDフラッシュとNORフラッシュの2種類があります。NANDフラッシュは、メモリカードやフラッシュドライブに使用されます。データはデバイスからシリアル形式でクロックアウトされるため、一般にNANDデバイスからの読取りには数サイクルが必要になります。このシーケンシャルな動作によってアクセスタイムが長くなりすぎるため、NANDフラッシュはプログラムコードの格納には適しません。これと対照的に、NORフラッシュは従来のバイトまたはワード幅のメモリに似ています。NORフラッシュは、ROMデバイスから読取りを行う場合と同様に、デバイスセレクトとアドレスをアサートして、アクセスタイムだけ待った後、バスからデータを読み取ることができます。MAXQプロセッサファミリで使用されているのは、NORフラッシュです。

MAXQプロセッサのフラッシュメモリ

MAXQプロセッサで使用されているフラッシュメモリブロックは、消去によって「1」状態になります。したがって、消去を行った後はブロック内のすべての位置に0xFFFFが格納されることになります。フラッシュ内の1つの位置にプログラミングを行うことによって、一部のビットが「1」から「0」状態に変化します。プログラム済みのビットを「1」状態に戻すには、ブロック全体を消去する必要があります。

電気的に消去可能なすべてのメモリデバイスにとって避けて通ることのできない問題が、耐久性です。具体的な技術によりますが、フラッシュメモリセルが永久に動作しなくなるまでに、少ないもので1000回、多いもので100万回の消去/プログラムサイクルに耐えることができます。したがって、フラッシュメモリをデータストレージに使用するすべての方式において、書込みサイクルがアレイ全体に均一に分散され、消去/プログラムが頻繁に行われる位置と行われない位置が生じないことを保証する必要があります。

ほとんどのフラッシュデバイスでは、以前にプログラムされた位置の中で任意の未プログラムのビットを「1」から「0」の状態に変更することが可能です。たとえば、0xFFFEという値がプログラムされている位置を、後から0x7FFEという値にプログラムする操作では、どのビットの値も「0」から「1」には変化しないため、ほとんどのデバイスではこの操作を行うことができます。しかし、MAXQファミリのデバイスで使用されているフラッシュでは、たとえ「0」のビットを「1」に戻そうとするものでなくても、すでにプログラム済みの位置に対する再プログラムは許されていません。前述のような書込みを試みた場合は失敗し、値は0xFFFEのままになります。

MAXQデバイスでこうしたプログラムの制限が設けられていることには、十分な理由があります。プログラム対象のメモリブロックは本来コードスペースとして使用されるものであるため、すでに書込み済みの位置に対する書込み操作はすべて禁止するのが賢明です。0xFFFFというインストラクションは無効なソースサブデコードを示すものであり、有効なコードブロック中に現われるとは考えられません。したがって、すでにプログラム済みの位置に対する書込みを阻止することは、コードブロックの完全性の維持に役立ちます。

MAXQ2000を使用する設計方式

このアプリケーションノートでは、MAXQデバイスの1つであるMAXQ2000を取り上げます。このマイクロコントローラは、16ビット×256ワード×128ブロックで構成された64KBのプログラムストレージを備えています。以下では、2種類の設計方式を示します。第1の方式は、較正データ、バージョン情報、および機能文字列などのように、1度書込みを行った後は製品のライフタイムにわたってあまり頻繁に変更されない情報に適するものです。第2の方式は、使用情報や詳細記録など、より頻繁に変化するデータを収容するために設計された汎用性の高い仕組みです。

方式1

課題:較正データを製品に格納する必要があるとします。ときどき製品の再較正が必要になるため、較正データは再書込み可能なメモリに格納する必要があります。

解決策:実はこれが、考えられる最も単純な場合です。MAXQ2000が備えるプログラムフラッシュアレイの中の、ワードアドレス0x7E00と0x7F00から始まる2つのブロックは、較正データの格納用に確保されています。較正データを保存するコマンドを初めて受信した際、MAXQ2000は両方のブロックをチェックして、両方とも空白であることを認識します。較正データは第1のブロックに保存されます。

較正データを保存する2回目のコマンドに対して、MAXQ2000はまた両方のブロックをチェックします。ブロック0が使用されていることを検出すると、較正データをブロック1にコピーして、ブロック0を消去します。

較正データの読取り要求を(たとえば起動時に)受信した場合、MAXQ2000は両方のブロックの読取りを行って、どちらが使用されているか判断します。どちらかの消去されていない方のブロックを使用して、デバイスが較正済みの状態に設定されます。

この方式の主なメリットは、その単純性にあります。起動時(または他の設定復元イベント発生時)にアプリケーションがブロックの設定を要求する場合には、このアプローチが有効です。読取りルーチンはワードポインタを受け取り、そのアドレスの値を返します。書込みルーチンはワードポインタを受け取り、そのアドレスに対する書込みサイクルを試行します。消去ルーチンは、単に両方のブロックを消去します。

この方式には、デメリットもあります。これらのルーチンが、極めて単純だということです。書込みが成功するかどうかを判断するための試みは行われません。単に書込みが試みられ、失敗した場合、問題を修正する試みは何も行われません。こうした制約があるため、この方式は空きブロックであることが分かっているブロックへの書込みにのみ使用されます。

方式2

課題:エネルギー消費量や、その他の頻繁に変化するデータを追跡するために、不揮発性ストレージが必要だとします。更新の頻度は、週に数回から日に数回です。この課題の良い例として、電気メータがあります。

解決策:これは、伝統的なEEPROMであっても何らかの補助が必要になる状況です。更新が頻繁であり、かつ電気的に消去可能なすべてのメモリ技術には限られた書込み寿命しかないという事実があるため、単一のEEPROMセルに対して書込みと消去を繰り返すわけには行かないという点が問題です。1時間に1回更新が行われる場合を考えてみましょう。書込み/消去サイクルの限界が1万回のEEPROMでは、わずか1年強で寿命が尽きてしまい、電気メータについて確立されている10年という設計目標に、まったく届かないことになります。

この問題に対する解決策の1つは、何らかの形の「ウェアレベリング」を実装することです。これは、単一の位置に対する書込みが繰り返されるのを防ぐアプローチです。代わりに、書込みサイクルをメモリアレイ全体に分散させるため、適切な指標を同じように分散させます。

ウェアレベリングは広く理解されている技術であり、まさにこの目的のためにフラッシュストレージデバイスで使用されています。実際のアルゴリズムは複雑であり、簡単に理解できるものではありません。しかし本稿の目的にとっては、大幅に単純化された仕組みで十分です。

アドレスによる参照の代わりに、この実装ではストレージアレイ中のデータ項目がデータエレメント番号によって参照されます。データエレメント番号は、データエレメントを一意に識別する任意の8ビット値です。したがって、この方式では最大255個のデータエレメントが存在可能になります(データエレメント0は予備として確保されています)。個々のデータエレメントには、データエレメント番号とデータエレメント長(16ビットワード数1、2、3、または4を示す2ビットのコード)が格納され、必要に応じてエラーマネージメントに使用することができる十分な空き領域が残された、2バイトのヘッダ(図1を参照)が含まれています。

図1. データエレメントヘッダの構造
図1. データエレメントヘッダの構造

データエレメントを書き込むためには、書き込むデータ、データエレメントの長さ、およびデータを書き込む位置を、書込みサブルーチンが把握している必要があります。データを書き込むアドレスの決定方法は単純です。データエレメントは(それが新しいエレメントでも既存のエレメントに対する更新でも)ストレージアレイの末尾に書き込まれます。書込み関数はアレイの末尾を探して、最後のレコードの直後に新しいデータエレメントを書き込みます。指定された長さのレコードを格納するのに十分なスペースがそのフラッシュページに残されていない場合は、ページエンドマーカが書き込まれて、新しいページがオープンされます。典型的なデータページの構造を図2に示します。

このデータページでは、データエレメント1が最初に書き込まれ、頻繁に更新されています。次にデータエレメント4が書き込まれ、1度も更新されていません。次にデータエレメント3が書き込まれ、7回更新されています。最後にデータエレメント2が書き込まれ、1度も更新されていません。

ページエンドマーカが存在するということは、データ書込みが試行されたが、データエレメントがそのページには入らない長さだったことを示しています。新しいページがオープンされ、そのデータエレメントが収容されているはずです。データ構造全体の末尾は、エレメントヘッダが存在すべき場所が空きエレメントになっていることによって示されます。

図2. 典型的なデータページ
図2. 典型的なデータページ

この方式は、重複レコードの問題に対処していないことに注意してください。これは、重複レコードが問題にならないためです。事実、重複レコードは読取りと書込みの両方のルーチンによって完全に無視されます。書込み時には、同じ番号のレコードがすでに存在するかどうかに関わらず、新しいレコードはアレイの最後に格納されます。読取り時には、要求されたレコード番号に一致する最後の(したがって最も新しい)レコードだけが取り出されます。

アレイからのデータエレメントの読取りは、書込みよりも多少複雑です。読取り関数は、エレメント番号と、そのデータエレメントの内容を書き込むアドレスを受け取ります。呼び出された読取り関数は、アレイを先頭から探索します。要求されたデータエレメントに一致するレコードを発見すると、そのアドレスを保存して探索を継続します。他にも一致するレコードを発見した場合、読取り関数は保存してあるアドレスを新しいアドレスに置き換えます。アレイの末尾に到達した時点で、保存されているアドレスは、要求されたレコードのコピーの中で最も最近書き込まれたものを指していることになります。読取り関数はこのデータを、関数呼出し時に渡されたバッファにコピーします。

これで、ストレージアレイとの間でレコードの格納と取出しを行うための、実際に動作する「ほぼ読取り専用」のメカニズムが示されたわけですが、まだ1つ問題が残っています。レコードの古いコピーによって占められているスペースを再利用するための仕組みが存在しないことです(レコードを削除するための仕組みも存在しませんが、この方式は組込みアプリケーションで動作するように構成されているため、削除はあまり重要な機能ではないと思われます)。ある程度スペースを回復しないと、割り当てられているスペースをすぐに使い果たしてしまいます。しかし、フラッシュメモリは1度に1ページ単位でしか消去することができないため、スペースを回復するためにはページ全体を消去する必要があります。任意のフラッシュページを消去する際には、有益な情報を削除してしまうリスクが伴うため、問題がさらに複雑化します。唯一の選択肢は、古いページを消去する前に、有効な情報を新しいページにコピーすることです。

古いレコードからのスペースの回復は、3段階のプロセスになります。最初に、新しいフラッシュページをオープンして、各データエレメントの最も新しいバージョンを新しいページにコピーします。次に、古いページを消去します。最後に、新しいページにページマーカを配置して、読取りルーチンが発見できるようにします。

第1のステップは少々複雑であるため、もう少し詳細な検討が必要です。このステップを実行する単純な方法として、2つのサブステップに分割することができます。第1に、RAMアレイを使用して、アレイ内の最も新しいレコードのレコード番号とアドレスを格納します。第2に、RAMアレイの中を順に参照して、最も新しいレコードを新しいフラッシュページにコピーして行きます。この手順は高速であり、比較的単純明快です。

この2つのサブステップによる方式の問題点は、MAXQ2000に内蔵されているRAMが1kワードだということです。上記の方式では、バッファ用に割当て可能なRAMのサイズに格納することができる個別データの量が限られてしまいます。これが容認できないのは明らかです。

このジレンマの解決策となる方法は、時間はかかりますが、ストレージアレイが(妥当な範囲で)どんなに大きくなっても関係なく動作します。RAM内にポインタのリストを作成する代わりに、個別エントリのそれぞれについて、コピー元アレイ内で複数パスの処理を行います。すなわち、コンパクト化のアルゴリズムは次のようになります。
  1. コピー元アレイからエレメントを1つ読み取る。
  2. コピー先アレイ内でそのエレメントを探す。見つかった場合、そのエレメントはすでに書き込まれている。コピー元ポインタをインクリメントして1に戻る。
  3. コピー元アレイを走査して、そのエレメントの最新のコピーを探す。
  4. データエレメントの最新のコピーをコピー先アレイに書き込む。
  5. コピー元ポインタをインクリメントして1に戻る。
最後には、それぞれの個別データエレメントに対して、正確に1つのエントリがコピー先アレイ内に存在する状態になります。詰込み後のページの具体例を図3に示します。これで、コピー元のページを安全に消去して、コピー先のアレイにページヘッダを書き込むことができます。

図3. スペース回復後、図2のデータページはこのようになります。
図3. スペース回復後、図2のデータページはこのようになります。

このプロセスは、格納されたデータにとって可能な限り安全なように構成されています。しかし、フラッシュデバイスを使用する際には、書込みまたは消去動作中の電源断という危険に対処する必要があります。電源が切れると、恐らく1個以上のページが破損したり(書込みの場合)、消去が不完全になります(消去操作の場合)。しかし、このコンパクト化操作は本質的な安全性を備えています。以下のシナリオを考察します。
  • 詰込み操作の途中で電源断が発生した場合、コピー元ページは完全に元のまま残ります。電源復旧後は、新たに書込みが行われたページを(ページヘッダが存在しないため)容易に特定して消去することが可能であり、再び詰込み操作を開始することができます。
  • 古いページの消去中に電源断が発生した場合、それらのページには恐らく無効なヘッダが含まれることになります。それらのページを消去して、新しいページにヘッダを付加することが可能です。
  • 新しいページに対するページヘッダの書込み中に電源断が発生した場合、データは元のまま残ります。ページヘッダの更新操作を再び開始することが可能です。
すなわち、不測の事態によって回復不能なアレイデータの破損が発生する可能性のある仕組みは使用されていません。

方式2の改良

ここで示したストレージサブシステムは、誤り検出の仕組みを備えていません。データエレメント識別子の中には、使用されていないビットが(すでに示したように6ビット)存在します。CRC6アルゴリズム(x6 + x + 1)を使用してデータエレメント全体のCRCを算出することによって、読取りまたは書込みエラーが発生していないことを保証することが可能です。このアルゴリズムは(マルチビット誤りを1/64の割合で見落とすため)特に堅牢なものではありませんが、現実に発生する可能性の高いエラーのほとんどは検出されることになります。

前述のシステムが持つもう1つの制約は、読取りアクセス時間が必然的に長くなる点です。読出しの都度、アレイ内のすべてのレコードを読み取って、最も新しいレコードを見つける必要があるためです。アクセス時間を改善する方法は3つあります。
  1. 前方ポインタ用として、データエレメント中に空白のワードを残しておく。値の更新時に、新しいエントリの位置を前方ポインタに書き込みます。これによって、連結リストの形でテーブルを参照することが可能になります。
  2. テーブルを逆方向に参照する。あとは単に、要求されたエレメントが最初に見つかった時点で参照を終了すれば良いことになります。
  3. 個別エレメントの数が少ない場合は、エレメントIDとポインタを格納するためのRAMアレイを起動時に作成する。その後のアクセスは非常に高速になります。単にRAMアレイを読み取ることで、どこからデータエレメントを取得すれば良いかを判断することができます。

結論

不揮発性データストレージは、すべての設計エンジニアがいつかは取り組む必要のある要素です。MAXQプロセッサは柔軟なフラッシュメモリを備えているため、もはや設定データの保存に小型のシリアルメモリを使用する理由はありません。



このアプリケーションノートの旧版が、2008年1月にEmbedded.comのWebサイトで発表されています。