u8g2 사용하기

    



# 용량관리

아두이노에서 "Global variables use 1669 bytes (81%) of dynamic memory"라는 메시지는 사용 중인 글로벌 변수가 동적 메모리(RAM)의 상당 부분을 차지하고 있음을 나타냅니다. 이는 메모리 부족 문제로 이어질 수 있으므로, 메모리 사용량을 최적화하는 것이 중요합니다.


메모리 사용량을 줄이기 위해 시도할 수 있는 몇 가지 방법은 다음과 같습니다:


1. **변수 크기 최적화**: 변수를 선언할 때 필요한 최소 크기의 데이터 타입을 사용합니다. 예를 들어, `int` 대신 `byte`나 `uint8_t`를 사용할 수 있습니다.


2. **정적 메모리 사용**: 가능하면 `PROGMEM`을 사용하여 상수 데이터(예: 문자열, 설정값)를 플래시 메모리에 저장합니다. 이렇게 하면 이러한 데이터가 RAM을 차지하지 않습니다.


3. **로컬 변수 사용**: 글로벌 변수 대신 함수 내부에 로컬 변수를 사용합니다. 로컬 변수는 해당 함수가 실행될 때만 메모리를 차지하고 함수가 종료되면 메모리가 해제됩니다.


4. **동적 할당 최소화**: `malloc`이나 `new`를 사용하는 동적 메모리 할당을 최소화합니다. 동적 할당은 메모리 관리를 복잡하게 만들고 메모리 누수의 위험을 증가시킵니다.


5. **불필요한 라이브러리 제거**: 사용하지 않는 라이브러리를 코드에서 제거합니다. 라이브러리는 종종 추가적인 메모리를 사용하기 때문입니다.


6. **배열 크기 조정**: 배열을 사용하는 경우, 배열의 크기를 실제로 필요한 최소한으로 조정합니다.


7. **싱글턴 패턴 사용**: 여러 인스턴스가 필요하지 않은 객체에 대해 싱글턴 패턴을 사용하여 단 하나의 인스턴스만을 유지합니다.


8. **코드 최적화**: 불필요한 코드를 제거하고, 효율적인 알고리즘을 사용하여 메모리 사용을 줄입니다.


9. **디버깅 메시지 최소화**: 시리얼 통신을 통한 디버깅 메시지는 문자열을 많이 사용할 수 있으므로, 이를 최소화합니다.


메모리 사용량을 최적화하는 것은 마이크로컨트롤러 프로그래밍의 중요한 부분이며, 프로그램의 안정성과 성능에 큰 영향을 미칩니다. 위의 방법들을 차례대로 시도하여 적용해보시기 바랍니다.


# `F()` 매크로 사용

아두이노의 `F()` 매크로를 사용하는 것은 특히 문자열을 처리할 때 동적 메모리(RAM) 사용을 최적화하는 데 도움이 됩니다. `U8g2` 라이브러리에서 `F()` 매크로를 사용하면, 문자열 데이터가 RAM 대신 프로그램 메모리(Flash memory)에 저장되어 RAM 사용을 줄일 수 있습니다.


### `F()` 매크로의 작동 방식

- 아두이노에서 문자열 리터럴은 기본적으로 RAM에 저장됩니다. RAM은 제한된 리소스이므로, 많은 문자열을 사용하는 프로그램은 RAM을 빠르게 소모할 수 있습니다.

- `F()` 매크로는 문자열 리터럴을 Flash 메모리에 저장하도록 컴파일러에 지시합니다. Flash 메모리는 프로그램 코드와 함께 저장되며, RAM보다 훨씬 넉넉합니다.


### 예시 사용법

```cpp

u8g2.drawStr(0, 20, F("Hello World"));

```

- 이 예시에서, `"Hello World"` 문자열은 `F()` 매크로를 사용하여 Flash 메모리에 저장됩니다. 따라서 이 문자열은 RAM을 소모하지 않습니다.


### `F()` 매크로 사용 시 고려사항

- `F()` 매크로는 문자열이 RAM 대신 Flash 메모리에 저장되도록 하기 때문에, RAM의 사용량을 줄일 수 있습니다.

- 그러나 Flash 메모리에 저장된 문자열에 접근하는 속도는 RAM에 저장된 문자열에 접근하는 속도보다 다소 느릴 수 있습니다. 이 점은 대부분의 응용 프로그램에서 문제가 되지 않지만, 고성능이 필요한 응용 프로그램에서는 고려해야 할 수 있습니다.


`F()` 매크로를 사용하는 것은 특히 많은 양의 문자열을 다룰 때 동적 메모리를 효과적으로 관리하는 데 매우 유용합니다.



아두이노에서 RAM이 부족할 경우 프로그램이 예상치 못하게 이상하게 작동할 수 있습니다. RAM 부족은 여러 가지 문제를 일으킬 수 있으며, 이는 특히 메모리가 제한적인 아두이노와 같은 임베디드 시스템에서 중요한 이슈가 될 수 있습니다.


### RAM 부족으로 인해 발생할 수 있는 문제들:


1. **변수 값의 무작위 변경**: 사용 가능한 메모리가 부족하면, 프로그램이 의도치 않게 메모리의 잘못된 부분을 덮어쓸 수 있습니다. 이로 인해 변수 값이 예상치 못하게 변경될 수 있습니다.


2. **프로그램 충돌 및 재시작**: 심각한 메모리 부족은 프로그램의 충돌을 일으키고, 아두이노가 예기치 않게 재시작될 수 있습니다.


3. **기능의 부적절한 동작**: 특히 문자열 처리나 대규모 데이터 구조를 사용하는 프로그램에서 메모리 부족은 기능이 제대로 동작하지 않게 만들 수 있습니다.


4. **메모리 누수**: 동적 메모리 할당을 사용하는 경우, 메모리 누수가 발생하여 점차 사용 가능한 RAM이 줄어들 수 있습니다.


### RAM 부족 문제 해결 방법:


1. **코드 최적화**: 불필요한 변수 제거, 메모리 사용을 줄이는 방식으로 코드를 최적화합니다.


2. **동적 할당 최소화**: 가능한 한 동적 메모리 할당을 피하고, 정적 할당을 사용합니다.


3. **데이터 타입 선택**: 변수에 필요 이상으로 큰 데이터 타입을 사용하지 않도록 주의합니다. 예를 들어, `int` 대신 `byte`나 `char`를 사용할 수 있습니다.


4. **PROGMEM 사용**: 상수 데이터를 PROGMEM을 사용하여 프로그램 메모리에 저장합니다.


5. **함수와 라이브러리 검토**: 메모리를 많이 사용하는 함수나 라이브러리를 검토하고, 더 효율적인 대안을 찾아봅니다.


6. **하드웨어 업그레이드**: 더 많은 메모리를 제공하는 아두이노 보드로 전환하는 것도 고려할 수 있습니다.


RAM 관리는 아두이노 프로그래밍의 중요한 부분입니다. 프로그램의 안정성과 신뢰성을 유지하기 위해 메모리 사용을 주의 깊게 관리해야 합니다.



`U8g2` 라이브러리에서 램(RAM)을 많이 사용하는 주된 이유는 디스플레이 버퍼를 램에 저장하기 때문입니다. `U8g2` 라이브러리는 그래픽을 그리기 위해 두 가지 주요 방식을 사용합니다: "풀 버퍼(full buffer)" 모드와 "페이지 버퍼(page buffer)" 모드.


### 풀 버퍼 모드

- 풀 버퍼 모드에서는 디스플레이의 전체 화면을 메모리에 저장하는 버퍼를 사용합니다.

- 이 모드는 디스플레이의 해상도에 비례하여 많은 양의 RAM을 사용합니다. 예를 들어, 128x64 픽셀 OLED 디스플레이를 사용하는 경우, 전체 화면을 표현하기 위해 1024바이트 (128x64/8)의 RAM이 필요합니다.

- 풀 버퍼 모드는 화면 전체를 빠르게 업데이트할 수 있지만, 대가로 많은 메모리를 사용합니다.


### 페이지 버퍼 모드

- 페이지 버퍼 모드에서는 디스플레이를 여러 개의 "페이지"로 나누고, 한 번에 하나의 페이지만 메모리에 저장합니다.

- 이 모드는 풀 버퍼 모드보다 적은 양의 RAM을 사용합니다. 하지만 화면을 업데이트하는 데 더 많은 시간이 소요될 수 있습니다.

- 페이지 버퍼 모드는 메모리가 제한적인 환경에서 유리합니다.


### 메모리 사용 최적화

- RAM 사용을 최소화하려면 페이지 버퍼 모드를 사용하는 것이 좋습니다. 

- 또한, 디스플레이의 해상도와 필요한 그래픽 기능에 따라 적절한 `U8g2` 생성자를 선택하는 것도 중요합니다.


`U8g2` 라이브러리의 버퍼 모드 선택은 사용 중인 아두이노 보드의 RAM 용량과 프로젝트의 요구 사항에 따라 결정되어야 합니다.


---

u8g2 사용하기

U8glib과 비교해서 확실히 쓰기 편하고 합리적이다

그리고 adafruit_ssd1306 라이브러리랑 좀 더 비슷해졌다


위키랑 문서들이 정말 친절하다

https://github.com/olikraus/u8g2/wiki/u8g2reference



drawXBMP 사용문제..

u8g->u8g2 되면서 비트맵 형식을 x bitmap으로 바뀌었는데 읽는 방식이 방향이 달라서 이미지가 뒤죽박죽으로 나온다

나랑 같은 사례

https://forum.arduino.cc/t/u8g2-drawxbmp-incorrect-bitmap-drawing/1012673/5


xbitmap 설명

https://en.wikipedia.org/wiki/X_BitMap


drawXBMP 사용을 권장하면서 기존의 drawbitmap drawbitmapP 중에 drawbitmapP만 날려버렸는데

progmem에 저장된 데이터를 SRAM으로 복사해와서 drawbitmap을 사용하라고 답변해놨는데

마음에 드는 해결책이 아니라서

기존의 비트맵을 x 비트맵으로 변환하는 변환기를 찾고 있다



<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEj5AjhKB97Ed1HfctBygoAOQQUFZS6v4IwBrus3YH3O-6ZEFbahbPjHGd2fFPI2VK1gcumAaz8Y0dtoq8c9k11_SM9_3YSJpqp66E4pDH3IOEvmqHSHYAWdyTeFRjYKGF-w_yDVlIfa2jWn4NDNiEZK4VZI-oczsi2kZq8sHO9nEUehVBGOJK27zAYEukKN" style="margin-left: 1em; margin-right: 1em;"><img data-original-height="558" data-original-width="1708" height="210" src="https://blogger.googleusercontent.com/img/a/AVvXsEj5AjhKB97Ed1HfctBygoAOQQUFZS6v4IwBrus3YH3O-6ZEFbahbPjHGd2fFPI2VK1gcumAaz8Y0dtoq8c9k11_SM9_3YSJpqp66E4pDH3IOEvmqHSHYAWdyTeFRjYKGF-w_yDVlIfa2jWn4NDNiEZK4VZI-oczsi2kZq8sHO9nEUehVBGOJK27zAYEukKN=w640-h210" width="640" /></a></div>

용량 차이 많이나서 좀 고민인데 라이브러리 용량 때문에 상당히 부담된다


스트링에 F()를 쓰면 메모리에 저장되서 동적메모리를 아낀다고 하는데 살짝 효과는 있긴한데..


다른글에서 본 조언

https://forum.arduino.cc/t/can-anyone-help-me-reduce-my-sketches-dynamic-memory-usage-please/609372/5

모든 변수를 살펴보고 거기에 공간을 절약할 수 있는지 확인하십시오. 
코드를 자세히 살펴보진 않았지만 분과 초 같은 것은 정수일 필요가 거의 없습니다. 바이트는 일반적으로 음수가 되지 않고 60을 초과하지 않는 값이면 충분합니다.
한 번만 사용하는 다른 변수도 있습니다.
여기서는 아날로그 포트에서 읽은 값을 저장하지만 이를 한 번만 사용하여 아날로그 포트의 전압을 계산한 다음 부동 변수에 저장합니다. 이 변수는 다시 한 번만 사용됩니다. if 문에 대한 비교입니다. 
(물론, 이 작업을 두 번 수행합니다. 한 번은 설정에서, 한 번은 루프에서 수행합니다). 다른 곳에서는 변수를 사용하지 않을 경우 if 문에 직접 AnalogRead()를 넣으면 동일한 결과를 얻을 수 있고 6바이트의 메모리를 절약할 수 있습니다.


프레임 버퍼-> 페이지 버퍼 로 변경하는게 절약된다고 한다


라이브러리가 기본적으로 75%정도는 차지하는거 같네


print나 Println 이나 둘다 기능 같은듯

println이 줄바꿈 안해줌


arduino-wont-work-properly-when-dynamic-memory-goes-above-70 라는 글

https://forum.arduino.cc/t/arduino-wont-work-properly-when-dynamic-memory-goes-above-70/478113/33




댓글

이 블로그의 인기 게시물

STUDY

vue

Capacitor 웹 기반 애플리케이션을 네이티브 앱으로 감싸고, 네이티브 기능에 접근할 수 있게 해주는 프레임워크