esp32 & 메모리

아두이노 메모리 종류

아두이노에는 3가지 종류의 메모리가 있습니다.

-Flash memory(program space) : 아두이노 스케치, 부트로더가 저장되는 메모리입니다. 비휠방성 메모리로 전원이 차단되어도 삭제가 되지 않습니다. ex: Serial.println(F("문자열이다"))하면 Flash로 보냄.

  • SRAM(static random access memory) : 컴퓨터에서 흔히 이야기하는 RAM입니다. 휘발성 메모리로 전원이 차단되면, 내용이 삭제됩니다. 아두이노 스케치를 실행할 때 필요한 각종 변수, 버퍼 등이 SRAM에 생성됩니다.

    SRAM은

    1. Static Segment : Code Segment, Data Segment(스케치가 사용하는 static 변수, 전역 변수, 리터럴상수, 심볼릭상수(const, define))
    2. Stack Segment : 지역(local) 변수와 서브 루틴 혹은 인터럽트 서비스 루틴들이 call되었을 때, 돌아가야 할 주소들을 저장하는 스택(stack) 영역 으로 나눌 수 있습니다.지역 변수, 형식 매개 변수, 임시 변수, 반환 주소
      단, 포인터 변수에 메모리를 할당하여 쓰면... 이 포인터는 힙 영역(Heap Segment) 주소 번지를 가르킴
    3. Heap Segment : malloc과 같이 메모리 할당을 받아 사용하는 힙(heap) 영역,
      -- 추가 프로그래밍 기억 영역 :https://rubberduck.tistory.com/15
  • EEPROM : 컴퓨터의 하드디스크와 같이 긴 시간 자료를 저장해두고 싶을 때 사용하는 메모리입니다. 비휘발성이며, 전원이 없어도 데이터가 유지됩니다. EEPROM은 아주 적은 공간을 제공하고 있어 프로그램 코드나 데이터들이 저장되어 사용되지는 못하고, EEPROM 라이브러리를 통하여 사용자들이 직접 사용할 수 있습니다.

SRAM 메모리 줄이는법

  1. int의 크기는 아두이노 8비트 보드에서는 2 바이트, 32비트 보드에서는 32비트의 크기를 갖습니다. 이를 byte로 사용하면 메모리 사용을 반으로 줄일 수 있습니다. 배열 데이터와 같은 크기가 큰 것들을 사용할 때 꼭 int를 사용하여야 하는지 다시 한번 고민하는 자세는 필요할 것 같습니다.

  2. 메시지를 나타낼 때, 읽기 편하고 이해하기 쉽게 나타내는 것도 좋은 프로그래밍 자세이지만 이를 코드로 표시하여 자세한 원인들은 미리 작성한 코드 표로 찾게 하는 것도 적은 리소스를 효율적으로 사용하는 기법일 것입니다.

  3. 공통으로 사용되는 문자열은 분리하여 static 혹은 글로벌로 만들고 바뀌는 문자열들은 문자열 array list로 만드는 것도 한 방안일 것입니다.
    [출처] 메모리 공간 : Memory Space|작성자 과객

SRAM 트러블슛팅

이전에 stak over flow 뜨기 전 마지노선 쯤 코드
아래 static, datasegment가 stack을 제외한 SRAM에서 heap과 static 사용량. 즉
39816(=전역(heap+static))+277864(지역(=stack)) = 327680 (= 총SRAM)

lolind32는 Flash 16MB로 엄청 여유로운데,스케치 프로그램이 864kB
사용하고 최대 1.3MB밖에 못 사용하네. 아마 뭔가 있는듯.

전역변수는 동적메모리 저 뜻이, 전역 변수 메모리는 SRAM(data,stack,heap 영역)으로 나눠지는데 data부분에 static변수, 전역 변수가 들어간다. (추후에 설명하지만, stakoverFlow 에러 해결한 실마리는 pointer 보다 우선 전역으로 돌렸다. char[20500] =20500byte 니까 20kb를 stack에서 전역으로..(앞으로 큰 변수는 전역에 정의한다.) 하단, 전역변수 전환으로 stakoverflow를 잡고난 후 보면 둘째줄에 전역변수가 60312바이트로 약 20000바이트가 늘어난게 보인다.

그래서 아두이노 로그가 지역변수가 287864->267386으로 줄어든게 보인다. )
뒤에 노란색 동그라미 처둔건 지역변수인줄 알았는데 보니깐 큰 의미 없는 것같다. (단순 플래쉬 메모리 사용하는 스케치 저장공단 압축한것 같음)

reference

변수와 메모리 사용, 주의사항 중요!!!!!!!!
http://www.hardcopyworld.com/gnuboard5/bbs/board.php?bo_table=lecture_pract&wr_id=14

메모리 할당에 대해 잘나옴

https://juahnpop.tistory.com/120
위 사이트 들어가면 신기하 게 한 사람의 출근과정으로 FLASH 메모리, SRAM, EEPROM 을 설명잘 해준다.
모든 잡다한 일정은 FLASH MEMORY고, 변수들 중에 상황에 따라 언제든 사라졌다 생겼다 해도 되는것들은 SRAM에 저장한다.
오늘할일이나 내일할일 처럼 꼭 기억되야 하는건 EEPROM에 저장하고, 직장동료와 하는 게임을 변수라 하면, 어떤 게임인가 즉 그 값을 사다리타기라 할때, 사다리타기가 꼭 고정되어야 한다면 상수 선언자 const 를 써서 상수를 사용한다.

lolind32 spec은 뭘까?

esp32
SRAM 520KB? -> 320KB
EEPROM 512 bytes? -> kb 단위는 넘을듯.. 찾는중
16MB Flash / 8MB PSRAM? 16MB detected 됬다는데 왜.,.?
External RAM 8MB
https://www.wemos.cc/en/latest/d32/d32_pro.html

참고 : https://m.blog.naver.com/cimygy/221677513320

메모리는 이상하게 같은 모델인데도 스펙이 다르게 나오네..
위에 아두이노에서 찍히는것과 대조해보면
SRAM 320KB 아래 사이트가 맞는듯

또 다른 lolin d32 스펙사이트
https://docs.platformio.org/en/latest/boards/espressif32/lolin_d32_pro.html

esp32
https://randomnerdtutorials.com/esp32-mqtt-publish-subscribe-arduino-ide/

ArduinoJson 사용해서 PubSubClient 넣는법:
How to use ArduinoJson with PubSubClient?
https://arduinojson.org/v6/how-to/use-arduinojson-with-pubsubclient/

포인터 사용법

  • 포인터 : 데이터 전달 바구니 처럼 사용.
아래처럼 정의했다가
int16_t* pD; //포인터 선언
int16_t data[2 + NUM_SENSOR];

pD = &data[0]; 
*pD = header; 
 &data[0]의 주소를 포인터 변수에 할당한다.
 그럼 pD는 data[0]의 주소를 가진다.
 그 포인터 변수에 간접참조 연산자 *를 붙여주면
 해당 주소를 바로 참조하게 되고, 어떤 값을 할당하면
 바로 포인터가 할당받은 주소 data[0] 에 할당하게 된다. 
 배열도 아래처럼 쓸수 있다.
   for (uint8_t i = 0; i < NUM_ROW; i++) {
    for (uint8_t j = 0; j < NUM_COLUMN; j++) {
      //dummy = (i*NUM_COLUMN + j + loopNum * 100) % 4096;
      pD = &data[i * NUM_COLUMN + j + 1]; *pD = (int16_t)dummy;
      포인터 변수pD로 data[0]부터 주소값을 &요렇게 할당받고
      *pD 간접참조 연산자(*) 붙여서 실제 data[i]에 대입할 '값'을 넣어준다
    }
  }

How to reduce memory usage?

읽어보면 좋음.
참조 : https://arduinojson.org/v6/how-to/reduce-memory-usage/

  1. deserializer 할때 const char*, String 같이 read-only 속성 피하고
    char [] 타입처럼 수정 가능한 자료형으로 받아라.
  2. 긴 strings leterals일땐 F("문자열")로 사용. 그러면 Flash memory를 사용하게 된다.
    또는 PROGMEM 사용해서 FlashMemory 적극 활용.
  3. stack을 heap보다 선호해라.
    heap할당과 할당해제는 오버해드나 파편화를 야기한다. RAM은 적게 쓰더라도.
    malloc(), new, and String 이런거 쓰는게 heap 할당하는거임. String이 heap 할당이네..
    4.전역변수를 피하라.
  4. 변수들의 사이즈를 줄여라.
    127보다 아래숫자라면
int value= 42; -> char value = 42; 로 사용

C++ const reference 변수와 그냥 변수의 차이점

주소 : https://hashcode.co.kr/questions/2212/c-const-reference-%EB%B3%80%EC%88%98%EC%99%80-%EA%B7%B8%EB%83%A5-%EB%B3%80%EC%88%98%EC%9D%98-%EC%B0%A8%EC%9D%B4%EC%A0%90

  1. const는 상수화라는 의미입니다.
    위의 경우 const Point& a 라고 지정하면, a의 레퍼런스 대상을 변경할 수 없게 한다라는 뜻이 됩니다.

  2. call by value vs. call by reference
    call by value 방식의 값 전달은 값을 복사해서 전달합니다.
    주의: 클래스 오브젝트의 call by value 전달을 위해서는 필히 복사생성자(Copy Constructor)를 구현해야만 합니다.
    인자 전달 후, 원본 값과 전혀 별개의 개체임으로 함수안에서 값을 변경해도, 원본 인자에 영향을 주지 않습니다.
    call by reference 방식의 값 전달은 원본의 값의 그대로 사용하며, 참조만 전달합니다. (C에서는 포인터로 이를 흉내내었으나, C++에서는 별도로 제공합니다.)
    원본을 전달하기 때문에, 함수안에서 개체에 조작을 행한경우, 함수 종료후에도 그 영향이 남아있게 됩니다.
    위 설명에서 본 것과 같이 값을 복사하는 행위가 없기 때문에 call by refernce가 call by value보다 빠릅니다.

String Class를 효율적으로 쓰기위한 8가지 팁

https://cpp4arduino.com/2018/11/21/eight-tips-to-use-the-string-class-efficiently.html

좋은 웹페이지 즐겨찾기