임베디드 시스템이란
특정한 기능을 수행하기 위해 하드웨어와 소프트웨어가 결합된 시스템을 말한다.
OS가 없는 임베디드 시스템에서의 main() 호출 과정
startup 코드에서 C 프로그램이 동작하는 환경을 만들어줌
crto.s => startup 코드 가 포함된 .elf , .hex 파일이 나와야 실행된다.
⚙️ Startup Code 실행 순서
1️⃣ 인터럽트 비활성화 (Disable)
→ 초기화 중 방해받지 않게 인터럽트 차단
2️⃣ rw_data 복사 (ROM → RAM)
→ 초기값이 있는 전역변수를 RAM으로 옮김
3️⃣ bss 영역 초기화 (0으로 채움) ex) int zero;
→ 초기값 없는 전역변수를 0으로 설정
4️⃣ Stack 영역 설정
→ 함수 호출, 지역변수 저장용 스택 공간 준비
5️⃣ Heap 영역 설정
→ 동적 메모리(malloc 등) 사용 준비
6️⃣ 인터럽트 활성화 (Enable)
→ 시스템 안정 후 인터럽트 허용
7️⃣ main() 함수 호출
→ 이제부터 사용자가 작성한 C 코드 실행 시작
참고 : 여기서 메모리 영역을 할당하려면 세그먼트의 시작과 끝을 알려주는 심볼들이 필요하다

이름 설명 Startup Code의 동작
| rw-data 영역 | 초기값이 있는 전역변수(int a = 10;)가 저장되는 실행용 공간 | ROM의 data 값을 이곳으로 복사 |
| ZI(bss) 영역 | 초기값 없는 전역변수(int b;) 저장 공간 | 0으로 초기화 (Clear) |
| Heap 영역 | malloc(), new 같은 동적 메모리 할당용 공간 | Heap 포인터 초기화 |
| Stack 영역 | 함수 호출, 지역 변수 저장용 공간 | Stack 포인터 초기화 |
실제 예시
extern unsigned int Image$$RO$$Base; // ro-base
extern unsigned int Image$$RO$$Limit; // ro-limit
extern unsigned int Image$$RW$$Base; // rw-base
extern unsigned int Image$$ZI$$Limit; // zi-limit
void startup(void)
{
unsigned int *src, *dst;
// 1️⃣ rw-data 복사 (ROM → RAM)
src = &Image$$RO$$Limit; // ROM에서 복사 시작
dst = &Image$$RW$$Base; // RAM에 쓸 위치
while (dst < &Image$$ZI$$Limit) {
*dst++ = *src++;
}
// 2️⃣ bss(zi) 영역 0으로 초기화
for (dst = &Image$$ZI$$Limit; dst < &Image$$ZI$$Limit; dst++) {
*dst = 0;
}
// 3️⃣ main() 호출
main();
}
ROM 실행 vs RAM 실행
용량이 중요할 때는 ROM 실행 속도가 중요할 땐 RAM 실행 일부만 RAM 실행도 존재
Mapped I/O
CPU가 주변장치(입출력 장치, 예: GPIO, UART, Timer 등)에 접근하는 방법
임베디드는 주로 메모리 맵 I/O 를 사용
두 방식의 차이

입출력 I/O는 일반 변수와 틀리다 ex) volatile int a = 1;
volatile은 “값이 언제든 외부 요인에 의해 바뀔 수 있으니,
컴파일러야 이 변수는 캐시하지 말고 매번 진짜 메모리에서 읽어라.” 라는 의미
* 왜 꼭 써야하냐면 컴파일러는 최적화를 하기 때문에 "이 변수는 안 바뀔거임"판단해 CPU 레지스터에 저장한다.
확장자 파일

각 파일의 내용 매우 중

EEPROM : 어떤 설정값 , 초기값 ex) 시트 위치, DTC 고정정보
.hex : 칩에 올라가는 코드
※디버깅 : 디버깅 파일은 매우매우 중요하다
ISP vs JTAG(디버깅)
ISP 는 그냥 코드 업로드용
JTAG 펌웨어 업로드 + 실시간 디버깅 하드웨어 테스트 가능
Atmega328p
아트메가 328p 데이터 시트
메모리 128KB Flash , 4KB SRAM , 4KB EEPROM
구분 종류 역할 내용이 언제/어떻게 저장됨
| Flash | 비휘발성 (전원 꺼져도 유지) | 프로그램 코드 저장 (명령어) | 컴파일 후 업로드(Flash에 굽힘) |
| SRAM | 휘발성 (전원 꺼지면 사라짐) | 변수, 스택, 실행 중 데이터 | 프로그램 실행 중 생성/삭제 |
| EEPROM | 비휘발성 | 사용자 데이터(설정값, 기록 등) | 코드에서 직접 저장/읽기 (eeprom_write) |
Atmega328p 는 하바드 구조
하바드 구조
MCU가 명령어 와 데이터를 어떻게 저장하고 읽는지
변수나 데이터는 다른 메모리에 들어 있고
CPU가 이 둘을 동시에 접근할 수 있게 만든 구조
폰 노이만 구조
코드(명령)와 데이터가 한 메모리 공간에 섞여 있고,
CPU가 한 번에 한쪽만 접근 가능 (한 버스 사용).
명령어 읽기(fetch) 와 데이터 읽기(load/store) 를 동시에 못 함.
아두이노 보드 핀맵

MCU Block Diagram

Flash SRAM 분리 > 하바드 구조
Peripheral(주변장치)
= CPU(코어) 에 “붙어서” 입출력, 제어, 통신, 타이머 같은 기능을 수행하는 하드웨어 장치
MCU Core

설명 : 프로그램 카운터가 Flash 메모리에서 명령어를 가져와 Register 과 decoder 가 이를 해석해 ALU가 볌용 레지스터를 통해 이를 수행하고 필요에 따라 SRAM에 접근을 하는 과정
'Atmega328p' 카테고리의 다른 글
| {Atmega328p}-Timer , Counter (0) | 2025.10.29 |
|---|---|
| {Atmega328p}-ADC (0) | 2025.10.26 |
| {Atmega328p}-ISR (0) | 2025.10.26 |
| {Atmega328p}-UART 통신 (0) | 2025.10.24 |
| {Atmega328p}-페리페럴 제어 GPIO , 레지스터 구조체 (0) | 2025.10.22 |