그라운드 임베디드 EN 유튜브 구독

노트 / 컴퓨터구조

메모리 맵: MCU의 모든 것은 주소가 있다

코드는 Flash에, 변수는 SRAM에, 주변장치 레지스터도 정해진 주소에 있습니다. 데이터시트의 메모리 맵 읽는 법.

GROUND EMBEDDED · 정리 노트컴퓨터구조 05메모리 맵 1주변장치 기본 주소 + 레지스터 오프셋 = 레지스터 주소 2GPIOA 0x4800_0000 + ODR 0x14 = 0…

32비트 Cortex-M은 0x0000_0000부터 0xFFFF_FFFF까지 4GB의 주소 공간을 가집니다. 실제 메모리는 일부지만 영역마다 용도가 정해져 있습니다.

주소 영역 STM32 예
0x0800_0000 코드 (Flash) 프로그램과 const 데이터
0x2000_0000 SRAM 전역 변수, 스택, 힙
0x4000_0000 주변장치 GPIO, 타이머, UART 레지스터
0xE000_0000 코어 주변장치 NVIC, SysTick, 디버그

데이터시트 읽기

레퍼런스 매뉴얼의 메모리 맵 표에서 "GPIOA 0x4002_0000 ~ 0x4002_03FF"를 찾고, 해당 장의 레지스터 표에서 "ODR 오프셋 0x14"를 찾으면 GPIOA_ODR의 주소는 0x4002_0014입니다. CMSIS 헤더의 GPIOA->ODR은 이 계산을 대신해 주는 것입니다.

디버깅에 쓰기

하드폴트가 났을 때 문제 주소가 0x2000_xxxx면 RAM, 0x4xxx_xxxx면 주변장치 접근입니다. 클럭을 켜지 않은 주변장치의 레지스터에 접근하면 버스 오류가 나는데, 주소만 보고도 원인을 짐작할 수 있습니다.

그림으로 보기: 주소 공간 한 줄

0x0000_0000코드Flash, 벡터 테이블0x2000_0000SRAM변수, 스택0x4000_0000주변장치GPIO, UART, 타이머0xE000_0000코어NVIC, SysTick
Cortex-M의 4GB 주소 공간. 코드, 변수, 주변장치가 모두 같은 주소 체계 안에 있어서 포인터 하나로 전부 접근합니다.

이 큰 구획은 모든 Cortex-M에서 같습니다. 그 안에서 어느 주소에 무엇을 놓을지는 칩 제조사가 정하고, 데이터시트의 "Memory map" 표에 적혀 있습니다.

레지스터 주소는 이렇게 만들어진다

주변장치 기본 주소 + 레지스터 오프셋 = 레지스터 주소
GPIOA 0x4800_0000  + ODR 0x14       = 0x4800_0014

제조사 헤더 파일은 이 계산을 구조체로 표현합니다.

typedef struct {
    volatile uint32_t MODER;    // +0x00
    volatile uint32_t OTYPER;   // +0x04
    volatile uint32_t OSPEEDR;  // +0x08
    volatile uint32_t PUPDR;    // +0x0C
    volatile uint32_t IDR;      // +0x10
    volatile uint32_t ODR;      // +0x14
} GPIO_TypeDef;

#define GPIOA ((GPIO_TypeDef *)0x48000000u)

GPIOA->ODR이라고 쓰면 컴파일러가 기본 주소에 0x14를 더해 접근합니다. 구조체 멤버의 순서와 크기가 레퍼런스 매뉴얼의 오프셋과 정확히 맞아야 합니다.

프로그램은 어디에 놓이는가

구역 내용 놓이는 곳
.text 코드 Flash
.rodata const 데이터, 문자열 Flash
.data 초깃값이 있는 전역 변수 RAM (초깃값은 Flash에 보관)
.bss 초깃값이 0인 전역 변수 RAM
스택, 힙 실행 중에 쓰는 공간 RAM

.data는 Flash와 RAM을 모두 차지합니다. 전원이 켜지면 스타트업 코드가 Flash에 보관된 초깃값을 RAM으로 복사하고, .bss를 0으로 채운 다음 main을 부릅니다. 전역 변수가 처음부터 값을 갖고 있는 것은 이 과정 덕분입니다.

무료 전자책이 주제를 한 권으로 이어 읽기 (PDF 3권)→

맵 파일 읽기

빌드하면 나오는 .map 파일에는 모든 함수와 변수의 주소, 크기가 적혀 있습니다.

  • Flash나 RAM이 부족할 때: 크기가 큰 순서로 정렬해 무엇이 자리를 차지하는지 찾습니다.
  • 하드폴트가 났을 때: 폴트가 난 주소가 어느 함수 안인지 찾습니다.
  • 변수가 깨질 때: 그 변수 바로 앞에 놓인 배열을 의심합니다.

비트 밴딩과 별칭

일부 Cortex-M3/M4에는 RAM과 주변장치의 비트 하나하나를 별도 주소로 접근하는 영역이 있습니다. 한 번의 쓰기로 비트 하나만 바꿀 수 있어 읽고-바꾸고-쓰기 사이에 인터럽트가 끼어드는 문제가 없습니다. 모든 칩에 있는 것은 아니므로 데이터시트를 확인합니다.

현업에서 자주 터지는 문제

  • 예약 영역 접근: 맵에 없는 주소를 읽으면 버스 폴트가 납니다.
  • 클럭이 꺼진 주변장치: 주소는 맞아도 읽으면 0, 써도 반영되지 않습니다.
  • 칩을 바꿨더니 동작 안 함: 같은 계열이라도 주변장치 기본 주소가 다를 수 있습니다. 헤더 파일을 칩에 맞는 것으로 바꿉니다.
  • 부트로더와 응용의 주소 겹침: 링커 스크립트의 Flash 시작 주소와 벡터 테이블 위치를 함께 옮겨야 합니다.
영상으로 이어 보기회로와 하드웨어 시리즈 8편전자제품 속 회로 소자는 어떻게 동작할까? · 저항 · 커패시터 · 인덕터 완벽 정리FREE PDF무료 전자책 3권 받기이 주제를 한 권으로 이어서 읽고 싶다면. BLDC 모터 제어, 직렬통신, 센서를 책 분량으로 묶었습니다. 이메일만 남기면 바로 받습니다.무료로 받기 →