[IoT] 커뮤트 큐브: 3편 아두이노 용량 의문점
당했나? 왜 용량이 작지!
내가 구매한 아두이노 보드는 Wemos D1 R32이다. 아두이노 우노 계열인데, ESP32가 내장되어있어, 블루투스와 와이파이를 사용할 수 있는 장점이 있다. 대략적인 스펙시트는 다음과 같다.
Form Factor: Arduino UNO and headers. CPU and Memory: Xtensa® 32-bit LX6 Dua-core processor, up to 600 DMIPS. Operating Voltage: (5~12)Vdc. I/O pins Voltage: 3.3V. 4-MByte SPI Flash, 448-KByte ROM, 520-KByte SRAM. Wi-Fi: 802.11 b/g/n/e/i. Bluetooth V4.2 BR/EDR and BLE specification. Interface: Micro USB connection. USB Bridge IC: CH340G.
가격이 6천원대로 저렴해서 싱글벙글 구매했다. 여기까지 좋았는데, 아두이노 IDE에서 테스트 코드를 컴파일 해보니
Sketch uses 884869 bytes (67%) of program storage space. Maximum is 1310720 bytes.
전체 용량이 1.3메가바이트밖에 안된다고 한다.
4메가 메모리라고 했는데 왜 1.3메가가 전체 용량인거지? 라는 생각이 들었고, 뻥파워(예전에 성행한 파워서플라이의 실제 성능이 떨어지는 제품군)처럼 스펙 부풀리기에 당했나? 싶었다.
이런 상황에서는 경험상, 높은 확률로 내가 모르는 내용이 있을 가능성이 있다. 그래서 자료를 찾아보았다.
아두이노의 메모리는 어떻게 구성되어 있을까?
대표적으로 아두이노(= 마이크로 컨트롤러) 에는 3가지의 저장공간이 있다.
- 플래시 메모리
- 아두이노의 프로그램(스케치)이 저장되는 곳이다.
- ATmega328칩을 사용하는 아두이노 우노는 32KB의 공간을 사용한다.
- ESP32칩을 사용하는 Wemos D1 R32는 4MB의 공간을 사용한다.(더 크다!)
- ESP32는 더 최근에 설계되었고 마이크로 컨트롤러 기능 외에도 WIFI와 같은 네트워크 기능을 내장하고 있어 우노보다 더 많은 메모리와 처리능력이 요구된다.
- SRAM
- SRAM에는 실행 중인 프로그램의 변수와 실행 스택을 저장하는데 사용된다. 즉 컴퓨터로 치면 RAM역할을 한다.
- 아두이노 우노에는 2kb의 SRAM을 사용한다.
- 아두이노 우노는 ATmega328칩을 사용하는데 이 칩은 SRAM을 내장하고 있다. SRAM은 DRAM에 비해 접근속도가 매우 빠르고 데이터 갱신이 필요 없다. SRAM은 보통 CPU의 캐시 메모리로 주로 사용된다.
-
Wemos D1 R32에는 ESP32칩을 사용하는데, 520KB의 SRAM을 사용한다.(더 크다!)
- 컴퓨터는 DRAM을 쓰는데 마이크로 컨트롤러는 SRAM을 쓰는 이유는 SRAM이 더 빠르고, 소비전력이 낮다. 비용은 비싸지만 어치피 CPU에 내장되어 있어서 DRAM없이 SRAM으로만 작동된다.
- ROM(EEPROM)
- 부트로더라는 프로그램이 들어있다. 기기의 전원을 켰을 때, 가장 먼저 실행되는 프로그램으로, 기본적인 세팅을 처리하고 사용자가 입력한(플래시메모리에 담긴) 프로그램(아두이노 스케치)을 로드하고 실행한다.
- ROM은 Read-Only Memory의 약자로, 읽을 수만 있고 쓸 수 없는 메모리를 이야기한다. 런타임 도중에 쓸 수 없다는 이야기 뿐만 아니라 공장 출하 이후에는 ROM은 개발자(사용자)가 직접 수정할 수가 없다. 내장된 데이터는 제조 과정중 마스크 프로그래밍을 통해 영구적으로 쓰여진다. 즉 영구적으로 써야한다.
- EEPROM은 뭘까? 개발자(사용자)가 데이터를 지우고 다시 프로그래밍할 수 있도록 하는 메모리이다. 용도는 ROM과 같지만 EEPROM은 개발자(사용자)가 원한다면 데이터를 수정할 수도 있다.
- 아두이노 우노에는 1KB의 EEPROM이 있다.
- Wemos D1 R32에는 448KB의 EEPROM이 있다.(4백배!)
- Wemos D1 R32에는 ESP32칩이 사용되고 ESP32칩에는 내장된 EEPROM은 없지만, 플래시 메모리의 일부를 EEPROM처럼 사용할 수 있다. 이유는 별도의 EEPROM을 제공하는 것보다 더 저렴하기 때문일 것이다.
- 다르게 보면 EEPROM은 쓰기 사이클 수가 제한되어 있다. 여러번 쓰기 작업을 하면 수명이 줄어들기 때문에 내구도가 더 좋은 플래시 메모리를 EEPROM으로 사용하는 것도 좋은 방법이다.
필요한 선행 지식은 위와 같다.
용량이 4MB라면서요! 왜 용량이 더 작아요!
Wemos R1 D32 스펙시트에는 플래시메모리가 4MB라면서 아두이노 IDE에서 컴파일을 해보니 최대 용량 1.3MB라고 출력됐다.
알고보니 플레시 메모리는 다음과 같이 구성되어 있다.
- 코드영역
- SPIFFS 파일시스템 영역
- EEPROM 영역
이 중 코드영역이 1.3MB로 할당되어있었다. 즉 각각 파티셔닝이라고 볼 수 있다.(윈도우의 C드라이브 D드라이브처럼)
우선 EEPROM 영역은 데이터 시트에 448KB라고 되어 있으니 전체 4096KB(4MB) 중 EEPROM 영역을 제외한 3648KB만 사용가능하다. 3648KB 용량 내에서도 코드 영역과 SPIFFS 파일시스템 영역이 파티셔닝된다. 파티셔닝의 옵션도 설정할 수 있는데 기본값으로 1.3메가바이트를 코드 영역에 할당하고 나머지를 SPIFFS 파일시스템 영역에 할당한다.
아하! 그럼 SPIFFS가 뭐길래?
그럼 SPIFFS는 뭐길래 코드영역보다 더 많은 공간을 차지하는 걸까?
SPIFFS는 이미지, 폰트 등의 파일 저장에 주로 사용된다. 이미지나 폰트는 코드보다 훨씬 큰 크기를 가지고 있다. 그래서 이미지를 기계어로서 코드영역에 넣어버리면 용량이 더욱 커져버린다. 매우 비효율적이다! 자세한 설명은 다음과 같다.
- 이미지 데이터 표현 방식: 이미지는 픽셀 정보로 구성되는데 각 픽셀은 색상값으로 표현된다. 이러한 정보를 기계어로 변환하면 상당한 데이터가 필요하게 된다.
- 코드 최적화를 통해 이미지를 기계어로 변환하더라도 용량을 더욱 줄일 수 있다. 하지만 코드 최적화는 굉장히 어려운 작업이고 항상 원하는 결과를 얻을 수 있을지는 알 수 없다.(이미지 상태에 따라서 최적화가 불가능한 경우)
- 예를들어 1024x768해상도의 24비트 RGB 이미지를 기계어로 변환하면 대략적으로 24MB의 데이터가 필요하다.
- 계산:
- 해상도: 1024 * 768
- 색상 심도: 24비트(각 8비트 삼색)
- 픽셀당 바이트: 24비트/8비트/바이트 = 3바이트
- 이미지 데이터 크기 = 1024 * 768 * 3 = 23049216Byte
- 약 22.05MB
- 기계어 변환 오버헤드: 10% 예상
- 전체 약 24MB 예상
- 계산:
- 동일한 이미지를 PNG 포맷으로 저장하면 1MB정도로 줄어든다.(24배 절약!)
- 기계어를 최대한 최적화하여 압축된 1MB와 비슷한 크기로 기계어 코드를 줄일 수 있지만, 항상 보장되지 않고 너무 어려운 작업이다.
결론적으로 이미지를 기계어로 변환하여 코드 영역에 넣는것은 용량낭비가 될 가능성이 높다. 따라서 코드 영역과 별도의 메모리 영역을 사용해 SPIFFS 파일시스템을 이용해 이미지를 PNG 포맷으로서 저장할 수 있도록 해준다.
SPIFFS 설명 본론!
우선 파일시스템이라는건 컴퓨터가 데이터(파일)을 효율적으로 관리할 수 있도록하는 시스템을 이야기한다. 운영체제에서 파일시스템을 제대로 작동시켜주기 때문에 컴퓨터에 이미지를 .png, .jpg 파일로 저장하고 관리할 수 있다. 대표적으로 윈도우는 FAT, NTFS를, 리눅스는 ext4같은 파일시스템을 사용한다.
SPIFFS는 파일시스템 중 하나로, 플래시메모리 기반 임베디드 시스템(혹은 사물인터넷 시스템)에서 사용하는 파일시스템이다. SPIFFS의 주요 특징은 작은 크기에 저전력으로 돌아가고, 간단한 사용이다. 왜 이런 파일시스템을 쓸까? 그냥 윈도우의 NTFS같은거 쓰면 안될까? 윈도우의 NTFS를 사용하면 좋겠지만 이는 더 많은 기능을 제공하므로 쓸데없이 더 복잡하고 더 많은 리소스를 사용할 수 있다. 따라서 임베디드 시스템에 특화된 가벼운 파일시스템, SPIFFS라는게 따로 존재한다.
결론은 이미지나 폰트를 마이크로컨트롤러에서 다루게 될 경우 코드영역에 넣어버리는 건 비효율적이다. 파일시스템 영역을 따로 만들어서 이미지, 폰트를 효율적으로 관리하기 위해 메모리의 영역을 구분지은 것이다.
오케이! 그럼 1.3MB로만 코드를 짜면 될까?!
나름 강력한(?) 아두이노 IDE는 코드영역과 파일시스템 영역의 파티셔닝을 커스텀할 수 있도록 지원한다.
위의 사진을 보면 Wemos D1 R32에서는 3가지 모드의 파티셔닝이 존재한다.
Default를 사용할 경우 1.3MB를 코드영역으로 사용하고 Minimal SPIFFS를 선택하면 파일시스템 영역이 줄어들어 더욱 늘어난 코드영역을 사용할 수 있다.
오늘 배운 내용은 정말 재밌었다.
Leave a comment