마이크로 컨트롤러의 다른 메모리 유형에는 무엇이 있습니까?


25

컴파일 후 C 코드에서 다양한 유형의 데이터를 넣는 서로 다른 메모리 세그먼트가 있습니다. 즉 : .text, .data, .bss, 스택과 힙. 각 세그먼트가 마이크로 컨트롤러 메모리에 어디에 있는지 알고 싶습니다. 즉, 메모리 유형이 RAM, NVRAM, ROM, EEPROM, FLASH 등을 고려할 때 어떤 데이터가 어떤 유형의 메모리로 들어가는가.

비슷한 질문에 대한 답을 찾았지만 각기 다른 메모리 유형의 내용이 무엇인지 설명하지 못했습니다.

모든 도움을 주시면 감사하겠습니다. 미리 감사드립니다!


1
NVRAM, ROM, EEPROM 및 Flash는 비 휘발성 메모리와 같은 점에서 거의 다른 이름입니다.
Lundin 2016 년

질문에 약간 접하지만, 특히 패치 또는 캘리브레이션 사용을 고려할 때 코드는 이들 중 상당수에 예외적으로 존재할 수 있습니다. 때로는 실행 전에 이동하고 때로는 실행됩니다.
Sean Houlihane 2016 년

@SeanHoulihane OP는 거의 항상 플래시에서 실행 되는 마이크로 컨트롤러에 대해 질문 하고 있습니다. 예를 들어 Linux를 실행하는 MB의 외부 RAM이있는 마이크로 프로세서 는 프로그램을 RAM에 복사하여 실행 가능 볼륨으로 작동하는 SD 카드에서 실행합니다.
tcrosley

@tcrosley 이제 TCM이 포함 된 마이크로 컨트롤러가 있으며 때로는 마이크로 컨트롤러가 더 큰 SoC의 일부입니다. 또한 mcu 부트 스트랩이 자체 스토리지에서 RAM으로 실행되도록 eMMC 장치와 같은 사례가 있다고 생각합니다 (2 년 전의 일부 전화 하드 브릭 메모리를 기반으로 함). 나는 직접적인 대답은 아니지만 동의합니다.하지만 일반적인 매핑은 어떤 식 으로든 어려운 규칙이 아닙니다.
Sean Houlihane 2016 년

1
텍스트와 rodata와 같은 읽기 전용 항목은 이상적으로 플래시로 가고 싶지만 .data와 .bss의 오프셋 및 크기도 거기에 있습니다 (그리고 복사하여 가져옵니다) 부트 스트랩 코드). 이러한 용어 (.text 등)는 마이크로 컨트롤러와 관련이 없으며 컴파일러 / 툴체인의 모든 대상에 적용되는 컴파일러 / 툴체인입니다. 하루가 끝나면 프로그래머는 작업이 진행되는 위치를 결정하고 일반적으로 링커 스크립트를 통해 툴체인에 알립니다.
old_timer 2016 년

답변:


38

.본문

.text 세그먼트에는 실제 코드가 포함되어 있으며 마이크로 컨트롤러 용 플래시 메모리로 프로그래밍되어 있습니다. 연속적이지 않은 여러 플래시 메모리 블록이있는 경우 하나 이상의 텍스트 세그먼트가있을 수 있습니다. 예를 들어 메모리 상단에 위치한 시작 벡터 및 인터럽트 벡터, 0에서 시작하는 코드; 부트 스트랩과 메인 프로그램을위한 별도의 섹션.

.bss 및 .data

함수 나 프로 시저 외부에 할당 할 수있는 세 가지 유형의 데이터가 있습니다. 첫 번째는 초기화되지 않은 데이터 (기록적으로 0으로 초기화 된 데이터도 포함하는 .bss라고 함)이고 두 번째는 초기화되지 않은 (비 bss) 또는 .data입니다. "bss"라는 이름은 60 년 전에 어셈블러에서 사용 된 "Block Started by Symbol"에서 유래했습니다. 이 두 영역은 모두 RAM에 있습니다.

프로그램이 컴파일 될 때 변수는이 두 가지 일반 영역 중 하나에 할당됩니다. 연결 단계 동안 모든 데이터 항목이 함께 수집됩니다. 초기화해야하는 모든 변수는 초기 값을 유지하기 위해 프로그램 메모리의 일부를 따로 보관하고 main ()이 호출되기 직전에 변수는 일반적으로 crt0이라는 모듈에 의해 초기화됩니다. bss 섹션은 동일한 시작 코드에 의해 모두 0으로 초기화됩니다.

몇 개의 마이크로 컨트롤러를 사용하면 RAM의 첫 페이지 (처음 256 개 위치, 때로는 0 페이지라고 함)에 액세스 할 수있는 더 짧은 명령어가 있습니다. 이러한 프로세서의 컴파일러는 near변수를 지정 하는 것과 같은 키워드를 예약 할 수 있습니다. 마찬가지로 포인터 레지스터를 통해 특정 영역 만 참조 할 수있는 마이크로 컨트롤러도 있으며 (추가 명령 필요) 이러한 변수가 지정 far됩니다. 마지막으로 일부 프로세서는 메모리 섹션을 비트 단위로 지정할 수 있으며 컴파일러는이를 키워드로 지정할 수 bit있습니다.

따라서 이러한 변수가 수집되는 .nearbss 및 .neardata 등과 같은 추가 세그먼트가있을 수 있습니다.

.rodata

함수 나 프로 시저 외부의 세 번째 유형의 데이터는 초기화 된 변수와 비슷하지만 읽기 전용이며 프로그램에서 수정할 수 없다는 점이 다릅니다. C 언어에서 이러한 변수는 const키워드를 사용하여 표시됩니다 . 일반적으로 프로그램 플래시 메모리의 일부로 저장됩니다. 때로는 .rodata (읽기 전용 데이터) 세그먼트의 일부로 식별되기도합니다. Harvard 아키텍처를 사용하는 마이크로 컨트롤러 에서 컴파일러는 특수 변수를 사용하여 이러한 변수에 액세스해야합니다.

스택 및 힙

스택과 힙은 모두 RAM에 배치됩니다. 프로세서의 아키텍처에 따라 스택이 커지거나 커질 수 있습니다. 자라면 RAM의 맨 아래에 배치됩니다. 자라면 RAM 끝에 배치됩니다. 힙은 변수에 할당되지 않은 나머지 RAM을 사용하고 스택의 반대 방향으로 커집니다. 스택 및 힙의 최대 크기는 일반적으로 링커 매개 변수로 지정할 수 있습니다.

스택에 배치 된 변수는 키워드없이 함수 나 프로 시저 내에 정의 된 모든 변수 static입니다. 한 번은 자동 변수 ( auto키워드) 라고 했지만 해당 키워드는 필요하지 않습니다. 역사적으로, auto그것은 C보다 먼저 B 언어의 일부 였으므로 존재했습니다. 기능 매개 변수도 스택에 배치됩니다.

다음은 RAM의 일반적인 레이아웃입니다 (특별한 페이지 0 섹션이 없다고 가정).

여기에 이미지 설명을 입력하십시오

EEPROM, ROM 및 NVRAM

플래시 메모리가 등장하기 전에 프로그램과 const 데이터 (.text 및 .rodata 세그먼트)를 저장하는 데 EEPROM (전기적으로 지울 수있는 프로그램 가능 읽기 전용 메모리)이 사용되었습니다. 이제는 사용 가능한 EEPROM의 양이 적습니다 (예 : 2KB-8KB 바이트). 일반적으로 전원을 껐다 켜도 유지해야하는 구성 데이터 또는 기타 소량의 데이터를 저장하는 데 사용됩니다. 주기. 이들은 프로그램에서 변수로 선언되지 않고 대신 마이크로 컨트롤러의 특수 레지스터를 사용하여 작성됩니다. EEPROM은 별도의 칩으로 구현할 수도 있고 SPI 또는 I²C 버스를 통해 액세스 할 수도 있습니다.

ROM은 출고시 프로그래밍 된 것 (사용자가 프로그래밍 할 수 없음)을 제외하고는 기본적으로 Flash와 동일합니다. 매우 큰 장치에만 사용됩니다.

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 달러입니다.


그것은 실제로 유용한 정보였습니다. 설명에 대한 참조를 제공해 주시겠습니까? 교과서 나 일기처럼 이것에 대해 더 많이 읽고 싶을 때 ..?
Soju T Varghese 2016 년

하나 더 질문, 당신은 다른 하나의 메모리 (EEPROM, NVRAM 및 플래시)에 비해 하나의 메모리의 장단점에 대한 아이디어를 줄 수 있습니까?
Soju T Varghese 2016 년

좋은 대답입니다. 나는 C 언어에서 구체적으로 어디로 가는지에 대해 더 자세하게 초점을 맞춘 보완적인 글을 올렸습니다.
Lundin

1
@SojuTVarghese 나는 대답을 업데이트하고 FRAM에 대한 정보도 포함시켰다.
tcrosley 2016 년

@Lundin은 동일한 세그먼트 이름 (예 : .rodata)을 사용하여 답변이 서로를 잘 보완합니다.
tcrosley 2016 년

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에는 프로그래머가 명시 적으로 초기화하지 않은 모든 정적 저장 기간 변수를 0으로 초기화해야한다는 규칙이 있습니다.

내재적으로 또는 명시 적으로 0으로 초기화 된 모든 정적 스토리지 기간 변수는로 끝납니다 .bss. 0이 아닌 값으로 명시 적으로 초기화 된 값은로 끝납니다 .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합니다. 포인팅 된 데이터가 읽기 전용인지 아니면 포인터 자체인지에 따라 두 가지 다른 종류를 허용하기 때문입니다. 플래시를 원할 때 실수로 포인터가 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에 ..? 내 이해에, 둘 다 프로그래머에 의해 초기화 된 정적 변수입니다. 그렇다면 차이점은 무엇입니까? @ 룬딘
소주 T Varghese

2
@SojuTVarghese .bss 데이터가 블록으로 0으로 초기화되기 때문에; d = 1과 같은 특정 값은 플래시에 저장해야합니다.
tcrosley 2016 년

@SojuTVarghese 설명이 추가되었습니다.
Lundin

@Lundin 또한 마지막 예제 코드에서 모든 초기화 된 값이 .text 또는 .rodata에 들어가고 해당 변수 만 .bss 또는 .data에 들어간다는 의미입니까? 그렇다면 변수와 해당 값이 서로 어떻게 매핑됩니까 (즉, .bss / .data와 .text / .rodata 세그먼트 사이)?
Soju T Varghese 2016 년

@SojuTVarghese No는 .data일반적으로 초기 값이 저장되는 소위로드 주소와 RAM에 소위 가상 주소 (실제로는 마이크로 컨트롤러에서는 가상이 아님)를 가지며, 실행시 변수가 저장됩니다. 시작하기 전에 main초기 값이로드 주소에서 가상 주소로 복사됩니다. 0 .bss을 저장할 필요가 없으므로 초기 값을 저장할 필요가 없습니다. sourceware.org/binutils/docs/ld/…
starblue

1

모든 데이터는 프로그래머가 선택한 메모리에 들어갈 수 있지만 일반적으로 데이터의 사용 프로필이 메모리의 읽기 / 쓰기 프로필과 일치하는 시스템이 가장 잘 작동합니다 (사용하려고 함).

예를 들어 프로그램 코드는 WFRM이며 (많은 사람이 거의 읽지 않음) 많은 코드가 있습니다. 이것은 플래시에 잘 맞습니다. ROM OTOH는 W 1 회 RM입니다.

스택과 힙은 작으며 읽기 및 쓰기가 많습니다. RAM에 가장 적합합니다.

EEPROM은 이러한 용도 중 어느 것도 적합하지 않지만 전원을 켤 때 발생하는 소량의 데이터 프로파일에 적합하므로 사용자 별 초기화 데이터 및 아마도 로깅 결과에 적합합니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.