Apa yang ada di berbagai jenis memori mikrokontroler?

25

Ada segmen memori yang berbeda di mana berbagai jenis data dimasukkan ke dalam dari kode C setelah kompilasi. Yaitu: .text, .data, .bss, stack dan heap. Saya hanya ingin tahu di mana masing-masing segmen ini akan berada dalam memori mikrokontroler. Yaitu, data mana yang masuk ke dalam jenis memori apa, mengingat jenis memori tersebut adalah RAM, NVRAM, ROM, EEPROM, FLASH dll.

Saya telah menemukan jawaban untuk pertanyaan serupa di sini, tetapi mereka gagal menjelaskan apa yang akan menjadi isi dari masing-masing jenis memori yang berbeda.

Segala jenis bantuan sangat dihargai. Terima kasih sebelumnya!

Soju T Varghese
sumber
1
NVRAM, ROM, EEPROM dan Flash cukup banyak nama yang berbeda untuk hal yang sama: memori non-volatile.
Lundin
Agak tangental terhadap pertanyaan, tetapi kode dapat (sangat) ada di hampir semua ini, terutama jika Anda mempertimbangkan tambalan atau penggunaan kalibrasi. Terkadang akan dipindahkan sebelum eksekusi, terkadang dieksekusi di tempat.
Sean Houlihane
@SeanHoulihane OP bertanya tentang mikrokontroler, yang hampir selalu mengeksekusi dari Flash (Anda memang memenuhi syarat komentar Anda dengan luar biasa). Prosesor mikro dengan MB RAM eksternal yang menjalankan Linux misalnya, akan menyalin program mereka ke dalam RAM untuk menjalankannya, mungkin dari kartu SD yang bertindak sebagai volume yang dapat dipasang.
tcrosley
@tcrosley Sekarang ada mikrokontroler dengan TCM, dan terkadang mikrokontroler adalah bagian dari SoC yang lebih besar. Saya juga curiga ada kasus-kasus seperti perangkat eMMC di mana MCU bootstraps sendiri untuk dijalankan dari RAM dari penyimpanannya sendiri (berdasarkan memori beberapa telepon hard-bricking dari beberapa tahun yang lalu). Saya setuju, ini bukan jawaban langsung - tapi saya pikir itu sangat relevan bahwa pemetaan yang khas tidak dengan cara apa pun aturan keras.
Sean Houlihane
1
tidak ada aturan untuk menghubungkan satu hal dengan yang lain, tentu saja hal-hal yang hanya baca seperti teks dan rodata idealnya ingin dimasukkan dalam flash, tetapi .data dan offset serta ukuran .bss juga ada di sana (dan kemudian disalin oleh kode bootstrap). istilah-istilah ini (.text, dll) tidak ada hubungannya dengan mikrokontroler itu adalah hal yang kompiler / toolchain yang berlaku untuk semua target dari kompiler / toolchains. pada akhirnya sang programmer memutuskan ke mana harus pergi dan menginformasikan toolchain melalui skrip linker biasanya.
old_timer

Jawaban:

38

.teks

Segmen .text berisi kode aktual, dan diprogram dalam memori Flash untuk mikrokontroler. Mungkin ada lebih dari satu segmen teks ketika ada beberapa blok, memori Flash yang tidak bersebelahan; misalnya vektor awal dan vektor interupsi yang terletak di bagian atas memori, dan kode mulai dari 0; atau bagian terpisah untuk bootstrap dan program utama.

.bs dan .data

Ada tiga jenis data yang dapat dialokasikan di luar fungsi atau prosedur; yang pertama adalah data yang tidak diinisialisasi (secara historis disebut .bss, yang juga mencakup 0 data yang diinisialisasi), dan yang kedua diinisialisasi (non-bss), atau .data. Nama "bss" secara historis berasal dari "Block Started by Symbol", yang digunakan dalam assembler sekitar 60 tahun yang lalu. Kedua area ini terletak di RAM.

Ketika sebuah program dikompilasi, variabel akan dialokasikan ke salah satu dari dua area umum ini. Selama tahap penautan, semua item data akan dikumpulkan bersama. Semua variabel yang perlu diinisialisasi akan memiliki sebagian memori program yang disisihkan untuk menampung nilai awal, dan tepat sebelum main () dipanggil, variabel akan diinisialisasi, biasanya oleh modul yang disebut crt0. Bagian bss diinisialisasi ke semua nol dengan kode startup yang sama.

Dengan beberapa mikrokontroler, ada instruksi yang lebih pendek yang memungkinkan akses ke halaman pertama (256 lokasi pertama, kadang-kadang disebut halaman 0) RAM. Kompiler untuk prosesor ini dapat memesan kata kunci seperti nearuntuk menunjuk variabel yang akan ditempatkan di sana. Demikian pula, ada juga mikrokontroler yang hanya dapat mereferensikan area tertentu melalui register pointer (membutuhkan instruksi tambahan), dan variabel-variabel tersebut ditunjuk far. Akhirnya, beberapa prosesor dapat menangani bagian memori sedikit demi sedikit dan kompiler akan memiliki cara untuk menentukan itu (seperti kata kunci bit).

Jadi mungkin ada segmen tambahan seperti .nearbss dan .neardata, dll., Di mana variabel-variabel ini dikumpulkan.

.rodata

Jenis ketiga data eksternal untuk suatu fungsi atau prosedur adalah seperti variabel yang diinisialisasi, kecuali itu hanya baca dan tidak dapat dimodifikasi oleh program. Dalam bahasa C, variabel-variabel ini dilambangkan dengan menggunakan constkata kunci. Mereka biasanya disimpan sebagai bagian dari memori flash program. Kadang-kadang mereka diidentifikasi sebagai bagian dari segmen .rodata (data hanya baca). Pada mikrokontroler yang menggunakan arsitektur Harvard , kompiler harus menggunakan instruksi khusus untuk mengakses variabel-variabel ini.

tumpukan dan tumpukan

Tumpukan dan tumpukan keduanya ditempatkan dalam RAM. Bergantung pada arsitektur prosesor, tumpukan dapat tumbuh, atau tumbuh. Jika itu tumbuh, itu akan ditempatkan di bagian bawah RAM. Jika itu tumbuh ke bawah, itu akan ditempatkan di akhir RAM. Heap akan menggunakan sisa RAM yang tidak dialokasikan untuk variabel, dan menumbuhkan arah yang berlawanan dari stack. Ukuran maksimum tumpukan dan tumpukan biasanya dapat ditentukan sebagai parameter tautan.

Variabel yang ditempatkan pada tumpukan adalah variabel apa pun yang ditentukan dalam fungsi atau prosedur tanpa kata kunci static. Mereka pernah disebut variabel otomatis ( autokata kunci), tetapi kata kunci itu tidak diperlukan. Secara historis, autoada karena itu adalah bagian dari bahasa B yang mendahului C, dan di sana diperlukan. Parameter fungsi juga ditempatkan di tumpukan.

Berikut adalah tata letak khas untuk RAM (dengan asumsi tidak ada bagian halaman 0 khusus):

masukkan deskripsi gambar di sini

EEPROM, ROM, dan NVRAM

Sebelum memori Flash muncul, EEPROM (memori hanya-baca yang dapat diprogram yang dapat dihapus secara listrik) digunakan untuk menyimpan program dan data const (segmen .text dan .rodata). Sekarang hanya ada sejumlah kecil (mis. 2KB hingga 8KB byte) dari EEPROM yang tersedia, jika ada, dan biasanya digunakan untuk menyimpan data konfigurasi atau sejumlah kecil data yang perlu dipertahankan melalui power-down power up siklus. Ini tidak dinyatakan sebagai variabel dalam program, tetapi ditulis untuk menggunakan register khusus dalam mikrokontroler. EEPROM juga dapat diimplementasikan dalam chip terpisah dan diakses melalui bus SPI atau I²C.

ROM pada dasarnya sama dengan Flash, kecuali diprogram di pabrik (tidak dapat diprogram oleh pengguna). Ini hanya digunakan untuk perangkat volume yang sangat tinggi.

NVRAM (RAM non-volatile) adalah alternatif untuk EEPROM, dan biasanya diimplementasikan sebagai IC eksternal. RAM reguler dapat dianggap non-volatile jika didukung oleh baterai; dalam hal ini tidak diperlukan metode akses khusus.

Meskipun data dapat disimpan ke Flash, memori Flash memiliki siklus penghapusan / program yang terbatas (1000 hingga 10.000) sehingga tidak benar-benar dirancang untuk itu. Ini juga membutuhkan blok memori untuk dihapus sekaligus, jadi tidak nyaman untuk memperbarui hanya beberapa byte. Ini dimaksudkan untuk variabel kode dan hanya-baca.

EEPROM memiliki batasan yang jauh lebih tinggi pada siklus penghapusan / program (100.000 hingga 1.000.000) sehingga jauh lebih baik untuk tujuan ini. Jika ada EEPROM tersedia di mikrokontroler dan itu cukup besar, itu adalah tempat Anda ingin menyimpan data yang tidak mudah menguap. Namun Anda juga harus menghapus dalam blok terlebih dahulu (biasanya 4KB) sebelum menulis.

Jika tidak ada EEPROM atau terlalu kecil, maka diperlukan chip eksternal. EEPROM 32KB hanya 66 ¢ dan dapat dihapus / ditulis hingga 1.000.000 kali. NVRAM dengan jumlah yang sama dengan operasi penghapus / program jauh lebih mahal (x10) NVRAM biasanya lebih cepat untuk membaca daripada EEPROM, tetapi lebih lambat untuk menulis. Mereka dapat ditulis ke satu byte pada suatu waktu, atau dalam blok.

Alternatif yang lebih baik untuk keduanya adalah FRAM (RAM feroelektrik), yang pada dasarnya memiliki siklus tulis yang tak terbatas (100 triliun) dan tidak ada penundaan penulisan. Ini tentang harga yang sama dengan NVRAM, sekitar $ 5 untuk 32KB.

tcrosley
sumber
Itu adalah informasi yang sangat berguna. Bisakah Anda memberikan referensi untuk penjelasan Anda? Suka buku teks atau jurnal, kalau-kalau saya ingin membaca lebih lanjut tentang ini ..?
Soju T Varghese
satu pertanyaan lagi, bisakah Anda memberikan gagasan tentang kelebihan atau kekurangan dari satu memori di atas yang lain (EEPROM, NVRAM dan FLASH)?
Soju T Varghese
Jawaban bagus. Saya memposting satu komplementer yang memfokuskan lebih detail pada apa yang terjadi di mana dalam bahasa C khusus.
Lundin
1
@ SojuTVarghese Saya memperbarui jawaban saya dan memasukkan beberapa informasi tentang FRAM juga.
tcrosley
@Lundin kami menggunakan nama segmen yang sama (mis. .Rodata) sehingga jawaban saling melengkapi dengan baik.
tcrosley
21

Sistem tertanam normal:

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.

Selain itu, biasanya ada segmen flash terpisah untuk kode start-up dan vektor interupsi.


Penjelasan:

Suatu variabel memiliki durasi penyimpanan statis jika dinyatakan sebagai staticatau jika berada pada lingkup file (kadang-kadang sembrono disebut "global"). C memiliki aturan yang menyatakan bahwa semua variabel durasi penyimpanan statis yang programmer tidak menginisialisasi secara eksplisit harus diinisialisasi ke nol.

Setiap variabel durasi penyimpanan statis yang diinisialisasi ke nol, secara implisit atau eksplisit, berakhir pada .bss. Sementara itu yang secara eksplisit diinisialisasi ke nilai non-nol berakhir di .data.

Contoh:

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
}

Harap diingat bahwa pengaturan non-standar yang sangat umum untuk sistem tertanam adalah memiliki "permulaan minimal", yang berarti bahwa program akan melewati semua inisialisasi objek dengan durasi penyimpanan statis. Oleh karena itu mungkin bijaksana untuk tidak pernah menulis program yang bergantung pada nilai inisialisasi variabel seperti itu, tetapi sebaliknya mengaturnya dalam "run-time" sebelum mereka digunakan untuk pertama kalinya.

Contoh segmen lainnya:

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
}

Variabel yang dapat disimpan di stack mungkin sering berakhir di register CPU selama optimasi. Sebagai patokan, variabel apa pun yang tidak diambil alamatnya dapat ditempatkan dalam register CPU.

Perhatikan bahwa pointer sedikit lebih rumit daripada variabel lain, karena mereka memungkinkan dua jenis yang berbeda const, tergantung pada apakah data menunjuk-harus hanya-baca, atau apakah pointer itu sendiri. Sangat penting untuk mengetahui perbedaannya sehingga pointer Anda tidak berakhir di RAM secara tidak sengaja, ketika Anda ingin mereka berada dalam flash.

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

Dalam kasus konstanta integer, daftar penginisialisasi, string literal dll, mereka mungkin berakhir di .text atau .rodata tergantung pada kompiler. Kemungkinan, mereka berakhir sebagai:

#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
Lundin
sumber
Saya tidak mengerti, dalam contoh kode pertama Anda, mengapa 'static int b = 0;' masuk ke .bss dan mengapa 'static int d = 1;' masuk ke data. ..? Dalam pemahaman saya, keduanya adalah variabel statis yang telah diinisialisasi oleh programmer .. lalu apa bedanya? @Lundin
Soju T Varghese
2
@ SojuTVarghese Karena .bss data diinisialisasi ke 0 sebagai blok; nilai spesifik seperti d = 1 harus disimpan dalam flash.
tcrosley
@ SojuTVarghese Menambahkan beberapa klarifikasi.
Lundin
@Lundin Juga, dari kode contoh terakhir Anda, apakah itu berarti bahwa semua nilai yang diinisialisasi masuk ke .text atau .rodata dan masing-masing variabelnya masing-masing masuk ke .bs atau .data? Jika demikian, bagaimana variabel dan nilai terkait dipetakan satu sama lain (yaitu, antara segmen .bss / .data dan .text / .rodata)?
Soju T Varghese
@ SojuTVarghese Tidak, .databiasanya memiliki alamat pemuatan yang disebut dalam flash, di mana nilai awal disimpan, dan apa yang disebut alamat virtual (tidak benar-benar virtual dalam mikrokontroler) dalam RAM, di mana variabel disimpan selama eksekusi. Sebelum mainmulai, nilai awal disalin dari alamat muat ke alamat virtual. Anda tidak perlu menyimpan angka nol, jadi .bsstidak perlu menyimpan nilai awalnya. sourceware.org/binutils/docs/ld/…
starblue
1

Sementara data apa pun dapat masuk ke memori apa pun yang dipilih programmer, umumnya sistem berfungsi paling baik (dan dimaksudkan untuk digunakan) di mana profil penggunaan data dicocokkan dengan profil baca / tulis memori.

Misalnya kode program adalah WFRM (tulis beberapa baca banyak), dan ada banyak. Ini cocok dengan FLASH. ROM OTOH adalah W sekali RM.

Stack dan heap kecil, dengan banyak membaca dan menulis. Itu akan cocok dengan RAM terbaik.

EEPROM tidak akan cocok dengan salah satu dari penggunaan itu dengan baik, tetapi itu cocok dengan profil sejumlah kecil data yang ada di seluruh power-up, jadi data inisialisasi khusus pengguna, dan mungkin mencatat hasil.

Neil_UK
sumber