같은 C/C++ 소스도 호스트와 MCU에서 다른 산출물이 된다
AI 호스트의 영상/추론 프로세스와 센서 가까이의 MCU 펌웨어는 실행 환경이 다르다. MCU(microcontroller)는 작은 프로세서와 메모리·주변장치를 묶은 제어용 소자다. 프로세서 명령 집합·메모리 배치·장치 레지스터·시작 코드가 타깃에 맞아야 한다. PC에서 컴파일이 통과했다는 사실은 MCU용 바이너리나 장치 동작을 검증한 것이 아니다.
그림 M04.01-1. 각 칸은 서로 다른 역할/근거다. 나란히 비교할 항목이며 위아래가 시간 순서를 뜻하지 않는다. 직접 제작한 개념도이며 본문의 조건과 함께 읽는다.
M01.03의 ABI/버퍼 계약을 타깃까지 확장한다. 빌드 호스트, 실제 타깃의 정확한 품번·컴파일러/도구 버전·헤더/링커 설정과 클록/보드 구성을 기록한다. 크로스 컴파일은 빌드한 곳과 실행할 타깃을 구분하는 방식이다. 호스트용 확장 라이브러리/실행 파일을 이름만 바꾸어 펌웨어로 사용하지 않는다. 이 단원은 새 C/C++ 문법이나 도구 설치를 요구하지 않는다.
저장 공간을 하나의 큰 RAM으로 더하지 않는다
사례 장치는 Microchip ATmega328P로 한정한다. Microchip 데이터시트 7810D-AVR-01/15의 용량/주소와 §7.3·§13.4를 확인한다. 다른 AVR·ARM·보드에 같은 수치를 복사하지 않는다. 이 설명에서1KiB는1024B다.
| 구분 | 이 사례의 용량 | 읽을 때의 의미 |
|---|---|---|
| Flash | 32KiB | 프로그램/초기값 이미지 등. SRAM 여유와 별도이며 부트/배치 확인 필요 |
| SRAM | 2KiB=2048B | 실행 중 데이터·버퍼·heap/stack의 예산 |
| EEPROM | 1KiB | 별도 비휘발 저장. SRAM 버퍼처럼 더하지 않음 |
전원이 꺼진 뒤 보존되는 저장과 실행 중 작업 공간은 다르다. 큰 로그/영상이 Flash에 들어간다는 이유로 같은 크기의 실행 버퍼가 SRAM에 확보되지는 않는다. 예를 들어80×60의1바이트 영상 한 장은4800B로, 이 장치의 SRAM 전체2048B보다 크다. 별도 스트리밍/타일·저장 설계 없이 통째로 보관할 수 없다. 이것은 모든 MCU에서 AI를 할 수 없다는 일반 명제가 아니라 해당 타깃·입력의 메모리 계약이다.
레지스터라는 이름의 서로 다른 대상을 구분한다
CPU 작업 레지스터는 연산에 쓰는 작은 저장소다. 주변장치 레지스터는 GPIO·타이머·통신장치의 설정/상태와 연결된다. 일반 SRAM 변수와 같은 숫자 주소 표기라도 접근의 의미가 다르다.
이 장치의 데이터 공간에서 CPU 작업 레지스터는0x0000~0x001F, I/O는0x0020~0x005F, 확장 I/O는0x0060~0x00FF다. 일반 SRAM은0x0100~0x08FF이므로 양 끝을 포함한 크기는0x08FF−0x0100+1=2048B다. 마지막 주소가0x08FF라는 이유로 그 아래 모두를 일반 SRAM 버퍼로 쓰면 안 된다.
같은 PORTB가 I/O 주소0x05와 데이터 공간 주소0x25로 표기된다. 이는 이 장치에서 두 공간의 표기가0x20만큼 다른 경우다. 어떤 명령/헤더·디버거의 주소 공간인지 먼저 확인한다. 두 숫자를 서로 다른 포트나 서로 교환 가능한 포인터 값으로 취급하지 않는다. ELF/링커 도구의 주소 표기도 타깃 문서의 공간 구분과 대조한다.
읽기/쓰기 가능·접근 폭·예약 비트·읽기/쓰기 부작용은 레지스터별로 다르다. 이 장치의 PINx에1을 쓰는 동작은 해당 PORTx 래치를 토글할 수 있다(§13.2.2). '입력 핀 레지스터니까 쓰면 무시되겠지'라는 추측은 틀리다. 이 사례는 쓰기 명령을 실행하는 실습이 아니다. 실제 연결의 전압/구동·핀 기능은 M03.04의 별도 명세를 확인한다.
ELF/map의 정적 사용량과 실행 중 최대치를 나눈다
AVR-LibC Memory Sections는 ELF의 섹션과 로드/실행 위치를 구분한다. 이 사례에서 .data의 초기값은 Flash의 이미지와 실행 SRAM에 관계하고, .bss는 일반적인 AVR-LibC 시작 코드가0으로 만들 실행 공간이다. .bss가 프로그램 이미지에 값 바이트를 담지 않는다고 SRAM도 안 쓰는 것은 아니다. 상수/라이브러리의 실제 배치는 타깃·링커 규칙으로 확인한다.
다음은 설명용으로 만든 예산/배치 표다. 실제 컴파일러 출력이나 측정된 최대 stack이 아니다. heap/stack이 표의 최대치를 동시에 쓴다고 가정하며 다른 예약 영역은 없다고 정했다.
| 영역 | 가상 데이터 주소/범위 | 사용량 |
|---|---|---|
.data | 0x0100~0x027F | 384B |
.bss | 0x0280~0x047F | 512B |
| heap 최대 | 0x0480~0x057F | 256B |
| 남겨 둔 간격 | 0x0580~0x067F | 256B |
| stack 최대 | 0x0680~0x08FF | 640B |
사용량은384+512+256+640=1792B, 여유는2048−1792=256B다. .data+.bss=896B만 보고 나머지1152B를 전부 새 버퍼로 배정할 수는 없다. 함수 호출·인터럽트 처리·라이브러리와 동적 할당이 쓰는 공간을 함께 고려한다. heap과 stack이 서로 향해 자라는 구성이라면 겹침도 검사해야 한다.
stack에512B가 더 필요해지면 총2304B로 SRAM을256B 초과한다. 기존256B 간격을 다 쓴 뒤 다른 영역과256B 겹치는 예산이다. 주소가 맞거나 빌드가 통과해도 이 실행 예산은 통과가 아니다. 역으로 여유256B가 양수라는 사실만으로 실제 최악 경로/인터럽트·라이브러리의 최대 사용량을 측정했다고 말하지 않는다.
실제 확인에는 정확한 ELF/map·설정/소스 지문과 정적 영역, 동적 할당·최대 stack의 산정/측정 방법·실행 조건을 남긴다. 도구가 자동으로 모든 실행 경로의 최대치를 증명해 준다고 가정하지 않는다. 여기서는 제공 표의 산술과 가정을 읽는 것이 기본 활동이다.
한 번의 읽기와 복합 갱신의 원자성은 다르다
ISR(interrupt service routine)은 인터럽트에 대응하는 처리 경로다. 메인 처리와 ISR이 같은 자료를 만지면 누가 어느 시점에 읽고 썼는지 보아야 한다. 아래는 특수 I/O가 아닌 일반8비트 SRAM flags의 합성 사건이다. bit0/bit1은 각자 다른 상태 표시라고 정했다.
| 순서 | 주체/사건 | flags/보관 값 |
|---|---|---|
| 1 | 초기 flags | 0x00 |
| 2 | 메인 처리가 flags를 읽어 보관 | 보관0x00 |
| 3 | ISR이 bit1을 켜서 저장 | flags=0x02 |
| 4 | 메인이 보관 값에 bit0만 반영해 저장 | flags=0x01 |
두 상태를 모두 남기려면0x03이어야 하지만 마지막은0x01이다. ISR의 bit1 갱신이 사라졌다. 하나의8비트 읽기/쓰기가 분리되지 않아도 읽기→계산→쓰기 전체가 중단 불가능하다는 뜻은 아니다. 다바이트 자료의 일관된 snapshot도 별도로 확인해야 한다.
AVR-LibC atomic 문서는 volatile 접근과 원자성을 구별한다. volatile을 붙인 사실만으로 상호배제·복합 갱신이나 다바이트 snapshot이 보장되지 않는다. 공유 자료의 소유자·폭/접근 순서와 짧은 임계 구간/일관된 복사 등 타깃에 맞는 방법을 검토하고 인터럽트 지연 영향도 확인한다. 여기서는 특정 코드를 안전하다고 실행/승인하지 않는다.
이 RAM 예제를 PINx나 특수 상태 플래그에 그대로 적용해서도 안 된다. 장치의 write-one-to-clear/toggle 등 규칙을 먼저 읽어야 한다. 일반 변수를 보호하는 방법과 주변장치의 접근 규약은 같은 문제의 한 답이 아니다.
센서 값에서 AI 호스트까지 출처를 보존한다
센서 펌웨어가 살아 있고 호스트에 문자열이 왔다고 측정/버퍼가 유효했다는 뜻은 아니다. 타깃/펌웨어·버퍼 범위/소유·관측 시각/오류를 함께 남긴다. 기존 4.4 센서 시간 정합의 드라이버/수신 시각도 MCU의 실제 측정과 구분한다.
학습 기록은 메모리 공간/주소 표기, 예산/가정과 초과, 공유 접근의 주체/순서, 실제 확인한 자료와 아직 하지 않은 빌드/장비 검증으로 나눈다. 다음 M04.02는 GPIO·UART·인터럽트·타이머의 시간/입출력을 다룬다. 펌웨어의 실행 자원과 호스트 AI 처리의 계약을 연결하되 두 환경을 같은 프로세스로 취급하지 않는다.