マイクロコントローラのさまざまなメモリタイプには何がありますか?


25

さまざまなタイプのデータがコンパイル後にCコードから入力されるさまざまなメモリセグメントがあります。すなわち:.text.data.bss、スタックとヒープ。これらの各セグメントがマイクロコントローラのメモリのどこにあるかを知りたいだけです。つまり、メモリタイプがRAM、NVRAM、ROM、EEPROM、フラッシュなどの場合、どのデータがどのタイプのメモリに入るかです。

私はここで同様の質問に対する答えを見つけましたが、彼らは異なるメモリタイプのそれぞれの内容がどうなるかを説明できませんでした。

どんな種類の助けも大歓迎です。前もって感謝します!


1
NVRAM、ROM、EEPROM、およびフラッシュは、同じもの、つまり不揮発性メモリを表す、まったく異なる名前です。
ランディン

質問にわずかに接していますが、特にパッチまたはキャリブレーションの使用を検討している場合、これらのコードのいずれか(例外的に)が存在する可能性があります。実行前に移動されることもあれば、所定の場所で実行されることもあります。
ショーンフーリハネ

@SeanHoulihane OPは、ほとんどの場合 Flashから実行されるマイクロコントローラーについて質問しています(コメントを例外的に修飾しました)。たとえば、Linuxを実行するMBの外部RAMを備えたマイクロプロセッサは、プログラムをRAMにコピーして実行します。おそらく、マウント可能なボリュームとして機能するSDカードから。
tcrosley

@tcrosley現在、TCMを備えたマイクロコントローラーがあり、マイクロコントローラーはより大きなSoCの一部である場合があります。また、eMMCデバイスのように、mcuが自身のストレージからRAMから実行するようにブートストラップするケースもあると思います(数年前の一部の電話のハードブリックのメモリに基づいて)。私は同意しますが、それは直接的な答えではありません-しかし、典型的なマッピングは決して厳格なルールではないということは非常に重要だと思います。
ショーンフーリハネ

1
あるものを別のものに接続するルールはありません。テキストやrodataのような読み取り専用のものはフラッシュするのが理想的ですが、.dataと.bssのオフセットとサイズもそこに行きます(そして、ブートストラップコード)。これらの用語(.textなど)はマイクロコントローラーとは関係ありません。コンパイラー/ツールチェーンのすべてのターゲットに適用されるのは、コンパイラー/ツールチェーンのことです。結局のところ、プログラマーはどこに行くかを決定し、通常はリンカースクリプトを介してツールチェーンに通知します。
old_timer

回答:


38

。テキスト

.textセグメントには実際のコードが含まれ、マイクロコントローラーのフラッシュメモリにプログラムされます。フラッシュメモリの連続していないブロックが複数ある場合、複数のテキストセグメントが存在する場合があります。たとえば、メモリの最上部にある開始ベクトルと割り込みベクトル、および0から始まるコード。または、ブートストラップとメインプログラム用の個別のセクション。

.bssおよび.data

関数またはプロシージャの外部に割り当てることができるデータには3つのタイプがあります。1つ目は初期化されていないデータ(歴史的には.bssと呼ばれ、0の初期化データも含まれます)、2つ目は初期化された(非BSS)、または.dataです。「bss」という名前は、歴史的には約60年前にアセンブラーで使用されていた「Block Started by Symbol」に由来しています。これらの領域は両方ともRAMにあります。

プログラムがコンパイルされると、変数はこれら2つの一般領域のいずれかに割り当てられます。リンク段階で、すべてのデータ項目が一緒に収集されます。初期化する必要のあるすべての変数には、初期値を保持するためにプログラムメモリの一部が確保され、main()が呼び出される直前に、変数は通常crt0というモジュールによって初期化されます。bssセクションは、同じスタートアップコードによってすべてゼロに初期化されます。

いくつかのマイクロコントローラーでは、RAMの最初のページ(最初の256の場所、ページ0と呼ばれることもあります)へのアクセスを許可する短い命令があります。これらのプロセッサのコンパイラは、nearそこに配置する変数を指定するなどのキーワードを予約する場合があります。同様に、ポインターレジスタを介して特定の領域のみを参照できる(追加の命令が必要)マイクロコントローラーもあり、そのような変数は指定されていfarます。最後に、一部のプロセッサはビット単位でメモリのセクションをアドレス指定でき、コンパイラはそれを指定する方法を持ちます(キーワードなどbit)。

そのため、これらの変数が収集される.nearbssや.neardataなどの追加のセグメントが存在する場合があります。

.rodata

関数またはプロシージャの外部の3番目のタイプのデータは、初期化された変数に似ていますが、読み取り専用であり、プログラムで変更できないことを除きます。C言語では、これらの変数はconstキーワードを使用して示されます。それらは通常、プログラムフラッシュメモリの一部として保存されます。時には、.rodata(読み取り専用データ)セグメントの一部として識別されます。ハーバードアーキテクチャを使用するマイクロコントローラでは、コンパイラは特別な命令を使用してこれらの変数にアクセスする必要があります。

スタックとヒープ

スタックとヒープは両方ともRAMに配置されます。プロセッサのアーキテクチャに応じて、スタックが大きくなったり小さくなったりする場合があります。大きくなると、RAMの下部に配置されます。大きくなると、RAMの最後に配置されます。ヒープは、変数に割り当てられていない残りのRAMを使用し、スタックの反対方向に成長します。スタックとヒープの最大サイズは、通常、リンカーパラメーターとして指定できます。

スタックに配置される変数は、キーワードなしで関数またはプロシージャ内で定義された変数ですstatic。それらはかつて自動変数(autoキーワード)と呼ばれていましたが、そのキーワードは必要ありません。歴史的には、autoCに先行するB言語の一部であり、そこで必要だったために存在します。関数パラメーターもスタックに配置されます。

RAMの一般的なレイアウトを次に示します(特別なページ0セクションがないと仮定)。

ここに画像の説明を入力してください

EEPROM、ROM、およびNVRAM

フラッシュメモリが登場する前は、プログラムとconstデータ(.textおよび.rodataセグメント)を保存するために、EEPROM(電気的に消去可能なプログラム可能な読み取り専用メモリ)が使用されていました。現在、使用可能なEEPROMはごくわずか(2KBから8KBバイトなど)しかありません。通常は、パワーダウン時の電源投入時に保持する必要がある構成データまたはその他の少量のデータを保存するために使用されます。サイクル。これらはプログラムで変数として宣言されていませんが、代わりにマイクロコントローラーの特殊レジスターを使用して書き込まれます。EEPROMは別のチップに実装し、SPIまたはI²Cバス経由でアクセスすることもできます。

ROMは、工場でプログラムされている(ユーザーがプログラムできない)ことを除いて、基本的にフラッシュと同じです。非常に大容量のデバイスにのみ使用されます。

NVRAM(不揮発性RAM)はEEPROMの代替であり、通常は外部ICとして実装されます。通常のRAMは、バッテリバックアップされている場合、不揮発性と見なされる場合があります。その場合、特別なアクセス方法は必要ありません。

データはフラッシュに保存できますが、フラッシュメモリの消去/プログラムサイクルの数は限られており(1000〜10,000)、そのために実際には設計されていません。また、メモリのブロックを一度に消去する必要があるため、数バイトだけを更新するのは不便です。コードと読み取り専用変数を対象としています。

EEPROMには、消去/プログラムサイクルの制限がはるかに高い(100,000〜1,000,000)ため、この目的にははるかに適しています。マイクロコントローラで使用可能なEEPROMが十分に大きく、不揮発性データを保存する場所です。ただし、書き込み前にブロック単位で消去する必要があります(通常は4KB)。

EEPROMがない場合、または小さすぎる場合は、外部チップが必要です。32KB EEPROM はわずか66¢で、1,000,000回まで消去/ 書き込み可能です。同数の消去/プログラム操作を備えたNVRAMは、はるかに高価(x10)です。NVRAMは通常、EEPROMよりも読み取りが高速ですが、書き込みが低速です。一度に1バイト、またはブロック単位で書き込まれます。

これらの両方のより良い代替手段は、本質的に無限の書き込みサイクル(100兆)と書き込み遅延のないFRAM(強誘電性RAM)です。NVRAMとほぼ同じ価格で、32KBで約5ドルです。


それは本当に役に立つ情報でした。あなたの説明への参照を提供してもらえますか?教科書や日記のように、これについてもっと読みたいと思ったら。
焼T Tバルゲーゼ

もう1つ質問がありますが、1つのメモリが他のメモリ(EEPROM、NVRAM、およびフラッシュ)よりも優れている点、または不利な点について考えてください。
焼酎T Varghese

いい答えだ。私は、C言語のどこに何が具体的に含まれるかについてより詳細に焦点を当てた補完的なものを投稿しました。
ランディン

1
@SojuTVarghese私は回答を更新し、FRAMに関する情報も含めました。
tcrosley

@Lundinでは、同じセグメント名(例:.rodata)を使用しているため、回答は互いにうまく補完しています。
tcrosley

21

通常の組み込みシステム:

Segment     Memory   Contents

.data       RAM      Explicitly initialized variables with static storage duration
.bss        RAM      Zero-initialized variables with static storage duration
.stack      RAM      Local variables and function call parameters
.heap       RAM      Dynamically allocated variables (usually not used in embedded systems)
.rodata     ROM      const variables with static storage duration. String literals.
.text       ROM      The program. Integer constants. Initializer lists.

また、通常、起動コードと割り込みベクター用に個別のフラッシュセグメントがあります。


説明:

変数はstatic、ファイルスコープとして宣言されている場合、またはファイルスコープに常駐している場合(場合によっては "グローバル"と呼ばれることもあります)、静的な保存期間を持ちます。Cには、プログラマーが明示的に初期化していないすべての静的ストレージ期間変数をゼロに初期化する必要があるという規則があります。

暗黙的または明示的にゼロに初期化されるすべての静的ストレージ期間変数は、最終的にになります.bss。明示的にゼロ以外の値に初期化されたものは、最終的にになります.data

例:

static int a;                // .bss
static int b = 0;            // .bss      
int c;                       // .bss
static int d = 1;            // .data
int e = 1;                   // .data

void func (void)
{
  static int x;              // .bss
  static int y = 0;          // .bss
  static int z = 1;          // .data
  static int* ptr = NULL;    // .bss
}

組み込みシステムの非常に一般的な非標準セットアップは「最小起動」であることに注意してください。つまり、プログラムは静的ストレージ期間を持つオブジェクトのすべての初期化をスキップます。したがって、そのような変数の初期化値に依存するプログラムを決して作成せず、それらを初めて使用する前に「実行時」に設定するのが賢明かもしれません。

他のセグメントの例:

const int a = 0;           // .rodata
const int b;               // .rodata (nonsense code but C allows it, unlike C++)
static const int c = 0;    // .rodata
static const int d = 1;    // .rodata

void func (int param)      // .stack
{
  int e;                   // .stack
  int f=0;                 // .stack
  int g=1;                 // .stack
  const int h=param;       // .stack
  static const int i=1;    // .rodata, static storage duration

  char* ptr;               // ptr goes to .stack
  ptr = malloc(1);         // pointed-at memory goes to .heap
}

スタックに配置できる変数は、多くの場合、最適化中にCPUレジスターに配置される場合があります。経験則として、アドレスが取得されていない変数はすべてCPUレジスタに配置できます。

ポインタは、ポイントconstされたデータを読み取り専用にするか、ポインタ自体を使用するかによって2種類のを許可するため、他の変数よりも少し複雑です。違いを知ることは非常に重要です。そうすれば、ポインターをフラッシュに入れたいときに偶然RAMにポインターが入らないようにすることができます。

int* j=0;                  // .bss
const int* k=0;            // .bss, non-const pointer to const data
int* const l=0;            // .rodata, const pointer to non-const data
const int* const m=0;      // .rodata, const pointer to const data

void (*fptr1)(void);       // .bss
void (*const fptr2)(void); // .rodata
void (const* fptr3)(void); // invalid, doesn't make sense since functions can't be modified

整数定数、初期化子リスト、文字列リテラルなどの場合、コンパイラに応じて.textまたは.rodataのいずれかになります。おそらく、彼らは次のようになります:

#define n 0                // .text
int o = 5;                 // 5 goes to .text (part of the instruction)
int p[] = {1,2,3};         // {1,2,3} goes to .text
char q[] = "hello";        // "hello" goes to .rodata

最初のコード例では、なぜ 'static int b = 0;'なのかわかりません。.bssに入り、なぜ 'static int d = 1;'になるのか .dataに入ります。私の理解では、どちらもプログラマーによって初期化された静的変数です。@Lundin
Soju T Varghese

2
@SojuTVarghese .bssデータはブロックとして0に初期化されるため。d = 1のような特定の値をフラッシュに保存する必要があります。
tcrosley

@SojuTVargheseいくつかの説明を追加しました。
ランディン

@Lundinまた、あなたの最後のサンプルコードから、すべての初期化された値が.textまたは.rodataに入り、それぞれの変数だけが.bssまたは.dataに入ることを意味しますか?その場合、変数とそれに対応する値はどのように互いにマッピングされますか(つまり、.bss / .dataと.text / .rodataセグメント間)?
焼T Tバルゲーゼ

@SojuTVargheseいいえ、.data通常、初期値が格納されるフラッシュのいわゆるロードアドレスと、実行中に変数が格納されるRAMのいわゆる仮想アドレス(マイクロコントローラーでは実際には仮想ではない)があります。main開始する前に、初期値がロードアドレスから仮想アドレスにコピーされます。ゼロを保存する必要.bssはないので、初期値を保存する必要はありません。sourceware.org/binutils/docs/ld/...
starblue

1

プログラマが選択した任意のメモリにデータを入力できますが、通常、システムはデータの使用プロファイルがメモリの読み取り/書き込みプロファイルと一致する場合に最適に機能します(使用することを意図しています)。

たとえば、プログラムコードはWFRM(読み取りが多く、読み取りが少ない)であり、多くのコードがあります。これはFLASHにぴったりです。ROM OTOHはW once RMです。

スタックとヒープは小さく、読み取りと書き込みがたくさんあります。RAMに最適です。

EEPROMはどちらの用途にも適していませんが、電源投入時に持続する少量のデータのプロファイルに適しているため、ユーザー固有の初期化データ、および結果のログ記録に適しています。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.