อะไรคือสิ่งที่อยู่ในหน่วยความจำชนิดต่าง ๆ ของไมโครคอนโทรลเลอร์?


25

มีเซ็กเมนต์หน่วยความจำที่แตกต่างกันซึ่งข้อมูลชนิดต่าง ๆ ถูกใส่ลงในรหัส C หลังจากการคอมไพล์ เช่น: .text, .data, .bssกองและกอง ฉันแค่อยากรู้ว่าแต่ละเซ็กเมนต์เหล่านี้จะอยู่ในหน่วยความจำไมโครคอนโทรลเลอร์ นั่นคือข้อมูลใดที่จะเข้าสู่หน่วยความจำประเภทใดเนื่องจากประเภทหน่วยความจำคือ RAM, NVRAM, ROM, EEPROM, FLASH เป็นต้น

ฉันได้พบคำตอบของคำถามที่คล้ายกันที่นี่ แต่พวกเขาไม่สามารถอธิบายได้ว่าเนื้อหาของหน่วยความจำแต่ละประเภทแตกต่างกันอย่างไร

ความช่วยเหลือใด ๆ ที่ชื่นชมอย่างมาก ขอบคุณล่วงหน้า!


1
NVRAM, ROM, EEPROM และ Flash เป็นชื่อที่แตกต่างกันมากสำหรับสิ่งเดียวกัน: หน่วยความจำแบบไม่ลบเลือน
Lundin

สัมผัสกับคำถามเล็กน้อย แต่รหัสสามารถ (ล้ำ) อยู่ใน prety มาก ๆ เหล่านี้โดยเฉพาะอย่างยิ่งถ้าคุณพิจารณาการใช้ปะหรือการสอบเทียบ บางครั้งมันจะถูกย้ายก่อนการประหารชีวิต
Sean Houlihane

@SeanHoulihane OP ถามเกี่ยวกับไมโครคอนโทรลเลอร์ซึ่งเกือบจะเต็มไปด้วย Flash (คุณได้รับความคิดเห็นของคุณด้วยคุณสมบัติที่ยอดเยี่ยม) ตัวประมวลผลขนาดเล็กที่มี MB ของ RAM ภายนอกที่ใช้ Linux จะคัดลอกโปรแกรมลงใน RAM เพื่อดำเนินการอาจเป็นการ์ด SD ที่ทำหน้าที่เป็นโวลุ่มที่สามารถเมานต์ได้
tcrosley

@tcrosley ขณะนี้มีไมโครคอนโทรลเลอร์ที่มี TCM และบางครั้งไมโครคอนโทรลเลอร์เป็นส่วนหนึ่งของ SoC ที่ใหญ่กว่า ฉันยังสงสัยว่ามีบางกรณีเช่นอุปกรณ์ eMMC ที่ mcu บูตตัวเองเพื่อเรียกใช้จาก RAM ออกจากที่จัดเก็บข้อมูลของตัวเอง ฉันเห็นด้วยไม่ใช่คำตอบโดยตรง - แต่ฉันคิดว่ามันเกี่ยวข้องมากกับการแมปทั่วไปที่ไม่ได้อยู่ในกฎที่ยาก
Sean Houlihane

1
ไม่มีกฎที่จะเชื่อมโยงสิ่งหนึ่งไปยังอีกสิ่งหนึ่งตรวจสอบให้แน่ใจว่าสิ่งที่อ่านอย่างเดียวเช่นข้อความและ rodata จะต้องการไปในแฟลช แต่. data และ offset และขนาดของ. bss ไปที่นั่นด้วย (จากนั้นคัดลอกโดย รหัส bootstrap) ข้อตกลงเหล่านี้ (.text ฯลฯ ) ไม่มีส่วนเกี่ยวข้องกับไมโครคอนโทรลเลอร์มันเป็นสิ่งที่คอมไพเลอร์ / Toolchain ที่ใช้กับเป้าหมายทั้งหมดของคอมไพเลอร์ / เครื่องมือ ในตอนท้ายของวันโปรแกรมเมอร์ตัดสินใจว่าจะไปที่ไหนและแจ้งให้ Toolchain ทราบผ่านสคริปต์ลิงเกอร์
old_timer

คำตอบ:


38

.Text

ส่วนของ. text มีรหัสจริงและถูกโปรแกรมลงในหน่วยความจำแฟลชสำหรับไมโครคอนโทรลเลอร์ อาจมีกลุ่มข้อความมากกว่าหนึ่งกลุ่มเมื่อมีหน่วยความจำแฟลชหลายบล็อกที่ต่อเนื่องกัน เช่นเวกเตอร์เริ่มต้นและเวกเตอร์ขัดจังหวะตั้งอยู่ที่ด้านบนของหน่วยความจำและรหัสเริ่มต้นที่ 0; หรือแยกส่วนสำหรับ bootstrap และโปรแกรมหลัก

.bss และ. data

มีข้อมูลสามประเภทที่สามารถจัดสรรภายนอกให้กับฟังก์ชันหรือกระบวนการได้ อันแรกคือข้อมูลที่ไม่ได้กำหนดค่าเริ่มต้น (เรียกว่า .bss ในอดีตซึ่งรวมถึงข้อมูลที่เริ่มต้นด้วย 0) และข้อมูลที่สองถูกเตรียมใช้งาน (ไม่ใช่ -ssss) หรือ. data ชื่อ "bss" ในอดีตมาจาก "Block Started by Symbol" ซึ่งใช้ในแอสเซมเบลอร์เมื่อประมาณ 60 ปีที่แล้ว ทั้งสองพื้นที่พื้นที่เหล่านี้จะอยู่ใน RAM

เมื่อโปรแกรมคอมไพล์แล้วตัวแปรจะถูกจัดสรรให้กับหนึ่งในสองพื้นที่ทั่วไปเหล่านี้ ในระหว่างขั้นตอนการเชื่อมโยงรายการข้อมูลทั้งหมดจะถูกรวบรวมพร้อมกัน ตัวแปรทั้งหมดที่จำเป็นต้องเริ่มต้นจะมีส่วนหนึ่งของหน่วยความจำของโปรแกรมที่ตั้งค่าไว้เพื่อเก็บค่าเริ่มต้นและก่อนที่จะเรียก main () ตัวแปรจะเริ่มต้นได้โดยทั่วไปโดยโมดูลที่เรียกว่า crt0 ส่วน bss นั้นเริ่มต้นเป็นศูนย์ทั้งหมดด้วยรหัสเริ่มต้นเดียวกัน

ด้วยไมโครคอนโทรลเลอร์บางตัวมีคำแนะนำสั้นกว่าที่อนุญาตให้เข้าถึงหน้าแรก (สถานที่ 256 แห่งแรกซึ่งบางครั้งเรียกว่าหน้า 0) ของ RAM คอมไพเลอร์สำหรับโปรเซสเซอร์เหล่านี้อาจจองคำหลักที่ต้องการnearกำหนดตัวแปรที่จะวางไว้ที่นั่น ในทำนองเดียวกันยังมีไมโครคอนโทรลเลอร์ที่สามารถอ้างอิงได้เพียงบางพื้นที่ผ่านการลงทะเบียนตัวชี้ (ต้องคำแนะนำพิเศษ) farและตัวแปรดังกล่าวจะกำหนด ในที่สุดโปรเซสเซอร์บางตัวสามารถระบุส่วนของหน่วยความจำทีละบิตและคอมไพเลอร์จะมีวิธีระบุว่า (เช่นคำหลักbit)

ดังนั้นอาจมีกลุ่มเพิ่มเติมเช่น .earbss และ .eardata เป็นต้นซึ่งมีการรวบรวมตัวแปรเหล่านี้

.rodata

ประเภทที่สามของข้อมูลภายนอกไปยังฟังก์ชั่นหรือขั้นตอนเป็นเหมือนตัวแปรเริ่มต้นยกเว้นมันเป็นแบบอ่านอย่างเดียวและไม่สามารถแก้ไขได้โดยโปรแกรม ในภาษา C ตัวแปรเหล่านี้จะถูกใช้แทนconstคำหลัก พวกเขามักจะเก็บไว้เป็นส่วนหนึ่งของหน่วยความจำแฟลชโปรแกรม บางครั้งพวกเขาถูกระบุว่าเป็นส่วนหนึ่งของกลุ่ม. ข้อมูล (อ่านอย่างเดียว) บนไมโครคอนโทรลเลอร์ที่ใช้สถาปัตยกรรม Harvardคอมไพเลอร์ต้องใช้คำสั่งพิเศษเพื่อเข้าถึงตัวแปรเหล่านี้

กองและกอง

ทั้ง stack และ heap นั้นถูกวางไว้ใน RAM สแต็กอาจโตขึ้นหรือเติบโตขึ้นอยู่กับสถาปัตยกรรมของโปรเซสเซอร์ หากโตขึ้นมันจะถูกวางไว้ที่ด้านล่างของ RAM ถ้ามันโตขึ้นมันจะถูกวางไว้ที่ส่วนท้ายของแรม ฮีปจะใช้ RAM ที่เหลือซึ่งไม่ได้จัดสรรให้กับตัวแปรและขยายทิศทางตรงกันข้ามของสแต็ก ขนาดสูงสุดของสแต็กและฮีปสามารถระบุเป็นพารามิเตอร์ตัวลิงก์ได้

ตัวแปรที่วางอยู่บนสแต็คที่มีตัวแปรใด ๆ staticที่กำหนดไว้ในฟังก์ชั่นหรือขั้นตอนโดยไม่ต้องคำหลัก พวกเขาเคยเรียกว่าตัวแปรอัตโนมัติ ( autoคำหลัก) แต่ไม่จำเป็นต้องใช้คำหลักนั้น ในอดีตautoมีอยู่เพราะเป็นส่วนหนึ่งของภาษา B ซึ่งนำหน้า C และจำเป็นต้องมี พารามิเตอร์ฟังก์ชั่นจะถูกวางไว้บนสแต็ก

นี่เป็นเลย์เอาต์ทั่วไปสำหรับ RAM (สมมติว่าไม่มีส่วนพิเศษหน้า 0):

ป้อนคำอธิบายรูปภาพที่นี่

EEPROM, ROM และ NVRAM

ก่อนที่หน่วยความจำแฟลชจะมาพร้อม EEPROM (หน่วยความจำแบบอ่านอย่างเดียวที่สามารถลบได้ด้วยระบบไฟฟ้าที่ใช้ลบได้) จะถูกใช้เพื่อจัดเก็บโปรแกรมและข้อมูล const (.text และ .rodata) ขณะนี้มี EEPROM เพียงเล็กน้อย (เช่น 2KB ถึง 8KB bytes) หากเป็นไปได้และโดยทั่วไปจะใช้สำหรับการจัดเก็บข้อมูลการกำหนดค่าหรือข้อมูลจำนวนเล็กน้อยอื่น ๆ ที่จำเป็นต้องเก็บไว้ในช่วงพลังงานลดลง วงจร สิ่งเหล่านี้ไม่ได้ถูกประกาศเป็นตัวแปรในโปรแกรม แต่จะถูกเขียนเพื่อใช้รีจิสเตอร์พิเศษในไมโครคอนโทรลเลอร์แทน EEPROM อาจนำไปใช้ในชิปที่แยกต่างหากและเข้าถึงได้ผ่านทาง SPI หรือI²Cบัส

ROM นั้นเหมือนกับแฟลชยกเว้นว่าได้รับการตั้งโปรแกรมจากโรงงาน (ผู้ใช้ไม่สามารถตั้งโปรแกรมได้) มันใช้สำหรับอุปกรณ์ที่มีปริมาณมากเท่านั้น

NVRAM (RAM แบบไม่ลบเลือน) เป็นทางเลือกแทน EEPROM และมักใช้เป็น IC ภายนอก แรมปกติอาจถูกพิจารณาว่าไม่ลบเลือนหากสำรองแบตเตอรี่; ในกรณีนั้นไม่จำเป็นต้องมีวิธีการเข้าถึงพิเศษ

แม้ว่าข้อมูลจะสามารถบันทึกลงใน Flash ได้ แต่หน่วยความจำแฟลชมีจำนวนการลบ / รอบการโปรแกรม จำกัด (1,000 ถึง 10,000) ดังนั้นจึงไม่ได้ออกแบบมาสำหรับสิ่งนั้น นอกจากนี้ยังต้องการบล็อกหน่วยความจำที่จะลบในครั้งเดียวดังนั้นจึงไม่สะดวกในการอัปเดตเพียงไม่กี่ไบต์ มันมีไว้สำหรับรหัสและตัวแปรอ่านอย่างเดียว

EEPROM มีข้อ จำกัด ที่สูงกว่ามากในการลบ / รอบโปรแกรม (100,000 ถึง 1,000,000) ดังนั้นจึงดีกว่ามากสำหรับวัตถุประสงค์นี้ หากมี EEPROM ในไมโครคอนโทรลเลอร์และมีขนาดใหญ่พอคุณสามารถบันทึกข้อมูลที่ไม่ลบเลือนได้ อย่างไรก็ตามคุณจะต้องลบบล็อกก่อน (โดยทั่วไปคือ 4KB) ก่อนที่จะเขียน

หากไม่มี EEPROM หรือเล็กเกินไปก็จำเป็นต้องใช้ชิปภายนอก 32KB EEPROM เพียง 66 ¢และสามารถลบ / เขียน 1,000,000 ครั้ง NVRAM ที่มีจำนวนการดำเนินการลบ / โปรแกรมเท่ากันนั้นมีราคาแพงกว่า (x10) NVRAMs มักจะอ่านได้เร็วกว่า EEPROM แต่จะช้ากว่าสำหรับการเขียน พวกเขาอาจถูกเขียนถึงหนึ่งไบต์ในเวลาหรือในบล็อก

ทางเลือกที่ดีกว่าสำหรับทั้งสองนี้คือ FRAM (ferroelectric RAM) ซึ่งมีวัฏจักรการเขียนที่ไม่มีที่สิ้นสุด (100 ล้านล้าน) และไม่มีความล่าช้าในการเขียน เป็นราคาเดียวกับ NVRAM ประมาณ $ 5 สำหรับ 32KB


นั่นเป็นข้อมูลที่เป็นประโยชน์จริง ๆ คุณช่วยอ้างอิงถึงคำอธิบายของคุณได้ไหม เช่นเดียวกับหนังสือหรือวารสารในกรณีที่ฉันต้องการอ่านเพิ่มเติมเกี่ยวกับเรื่องนี้ .. ?
Soju T Varghese

อีกหนึ่งคำถามคุณช่วยให้คุณได้ทราบถึงข้อดีหรือข้อเสียของหน่วยความจำหนึ่งในอีกหน่วยความจำ (EEPROM, NVRAM และ FLASH)
Soju T Varghese

คำตอบที่ดี ฉันโพสต์ข้อความเสริมซึ่งเน้นรายละเอียดเพิ่มเติมเกี่ยวกับสิ่งที่เกิดขึ้นในภาษา C โดยเฉพาะ
Lundin

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 register ระหว่างการปรับให้เหมาะสม ตามกฎของหัวแม่มือตัวแปรใด ๆ ที่ไม่มีที่อยู่ของมันสามารถอยู่ในการลงทะเบียนของ CPU

โปรดทราบว่าพอยน์เตอร์นั้นค่อนข้างซับซ้อนกว่าตัวแปรอื่น ๆ เนื่องจากอนุญาตให้มีสองชนิดที่แตกต่างกันconstขึ้นอยู่กับว่าข้อมูลที่ชี้ไปที่ควรเป็นแบบอ่านอย่างเดียวหรือถ้าตัวชี้ควรเป็น มันสำคัญมากที่จะต้องทราบความแตกต่างเพื่อให้พอยน์เตอร์ของคุณไม่ได้อยู่ใน 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 เนื่องจากข้อมูล. bbs เริ่มต้นเป็น 0 เป็นบล็อก ค่าเฉพาะเช่น d = 1 จะต้องเก็บไว้ในแฟลช
tcrosley

@SojuTVarghese เพิ่มคำอธิบายบางอย่าง
Lundin

@Lundin จากรหัสตัวอย่างล่าสุดของคุณหมายความว่าค่าเริ่มต้นทั้งหมดไปที่. text หรือ .rodata และตัวแปรตามลำดับจะอยู่ใน. bbs หรือ. data หากเป็นเช่นนั้นตัวแปรและค่าที่เกี่ยวข้องของพวกเขาจะถูกแมปเข้ากับกันอย่างไร (เช่นระหว่างกลุ่ม. bbs / .data และ. text / .rodata)
Soju T Varghese

@SojuTVarghese ไม่.dataโดยทั่วไปจะมีที่อยู่โหลดที่เรียกว่าในแฟลชที่เก็บค่าเริ่มต้นและที่อยู่เสมือนที่เรียกว่า (ไม่จริงเสมือนในไมโครคอนโทรลเลอร์) ใน RAM ที่ตัวแปรจะถูกเก็บไว้ในระหว่างการดำเนินการ ก่อนที่จะmainเริ่มค่าเริ่มต้นจะถูกคัดลอกจากที่อยู่โหลดไปยังที่อยู่เสมือน คุณไม่จำเป็นต้องเก็บค่าศูนย์ดังนั้น.bssไม่จำเป็นต้องเก็บค่าเริ่มต้น sourceware.org/binutils/docs/ld/…
starblue

1

ในขณะที่ข้อมูลใด ๆ สามารถเข้าไปในหน่วยความจำใด ๆ ที่โปรแกรมเมอร์เลือกโดยทั่วไประบบจะทำงานได้ดีที่สุด (และตั้งใจจะใช้) โดยที่โปรไฟล์การใช้งานของข้อมูลตรงกับโปรไฟล์การอ่าน / เขียนของหน่วยความจำ

ตัวอย่างเช่นรหัสโปรแกรมคือ WFRM (เขียนน้อยมากอ่านมาก) และมีจำนวนมาก เหมาะกับ FLASH อย่างนี้ ROM OTOH คือ W ครั้งเดียว RM

กองซ้อนและกองเล็กพร้อมการอ่านและเขียนจำนวนมาก นั่นจะพอดีกับ RAM ที่ดีที่สุด

EEPROM จะไม่เหมาะกับการใช้งานอย่างใดอย่างหนึ่ง แต่จะเหมาะสมกับโปรไฟล์ของข้อมูลจำนวนเล็กน้อยที่เกี่ยวข้องกับการเพิ่มพลังดังนั้นข้อมูลการเริ่มต้นใช้งานเฉพาะของผู้ใช้และอาจบันทึกผลลัพธ์

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.