본문 바로가기
ESP32/ESP32

ESP32 Deep Sleep 구현하기 - Timer Wake Up

by 빈이쥬 2024. 10. 21.

ESP32를 Deep Sleep 모드로 전환하는 방법을 알아보겠습니다.

Deep Sleep 모드 소개

ESP32는 다음과 같은 다양한 전원 모드로 전환할 수 있습니다

  • Active mode
  • Modem Sleep mode
  • Light Sleep mode
  • Deep Sleep mode
  • Hibernation mode

ESP32 데이터시트에서 5가지 모드를 비교할 수 있습니다.

 

ESP32 데이터시트에서 다음과 같은 다양한 모드의 전력 소비를 비교하는 표를 확인할 수 있습니다.

 

활성 모드에서의 전력 소비를 비교한 표 입니다. 

왜 Deep Sleep 모드를 사용해야 할까요

ESP32를 활성 모드로 배터리로 운영하는 것은 이상적이지 않습니다. 배터리의 전력이 매우 빨리 소모될 것입니다.

ESP32를 Deep Sleep 모드로 전환하면 전력 소비가 줄어들어 배터리가 더 오래 지속됩니다.

Deep Sleep 모드에서는 CPU와 Wi-Fi 활동이 중단되지만, 초저전력(ULP) 보조 프로세서는 여전히 전원이 공급될 수 있습니다.

Deep Sleep 모드에서 RTC 메모리(RTC 메모리)는 계속 전원이 공급되므로, ULP 보조 프로세서 프로그램을 작성하고 RTC 메모리에 저장하여 주변 장치, 내부 타이머 및 내부 센서에 접근할 수 있습니다. 이 작동 모드는 외부 이벤트, 타이머 또는 둘 다에 의해 메인 CPU를 깨우면서 최소한의 전력 소비를 유지해야 할 때 유용합니다.

RTC_GPIO 핀

Deep Sleep 모드 동안 ESP32의 일부 핀은 ULP 보조 프로세서에 의해 사용될 수 있습니다. 

RTC핀은 파란색 상자로 확인 할수 있습니다. 있습니다.

 

Wake up 방법

ESP32를 Deep Sleep 모드로 전환한 후에는 여러 가지 방법으로 깨울 수 있습니다:

  • 타이머를 사용하여 ESP32를 정해진 주기로 깨우기
  • 터치 핀 사용
  • 외부 웨이크업 소스를 사용: 단일 외부 웨이크업 또는 여러 외부 웨이크업 소스 중에서 선택 가능
  • ULP 보조 프로세서를 사용하여 깨우기

Deep Sleep 스케치 작성

ESP32를 Deep Sleep 모드로 전환하고 다시 깨우는 스케치를 작성하려면 다음 사항을 염두에 두어야 합니다

  1. 어떤 것이 ESP32를 깨울지 설정해야 하며, 하나 또는 여러 개의 웨이크업 소스를 사용할 수 있습니다.
  2. Deep Sleep 동안 어떤 주변 장치를 종료하거나 유지할지 결정할 수 있습니다. 기본적으로 ESP32는 정의된 웨이크업 소스와 필요 없는 주변 장치의 전원을 자동으로 차단합니다.
  3. 마지막으로 esp_deep_sleep_start() 함수를 사용하여 ESP32를 Deep Sleep 모드로 전환합니다.

Timer Wake UP

ESP32는 Deep Sleep 모드에 들어가고 정해진 주기로 다시 깨울 수 있습니다. 

Timer Wake UP 활성화

Arduino IDE에서는 다음 함수를 사용하여 마이크로초 단위로 수면 시간을 지정하여 정해진 시간 후에 깨우도록 설정합니다. 

esp_sleep_enable_timer_wakeup(time_in_us)
 

코드

다음은 라이브러리의 예제를 사용하여 이 기능을 구현하는 방법을 살펴보겠습니다.
Arduino IDE를 열고 파일 > 예제 > ESP32 Deep Sleep로 가서 TimerWakeUp 스케치를 엽니다.

#define uS_TO_S_FACTOR 1000000  /* 마이크로초를 초로 변환하기 위한 변환 계수 */
#define TIME_TO_SLEEP  5        /* ESP32가 수면 상태로 들어가는 시간 (초 단위) */

RTC_DATA_ATTR int bootCount = 0;

/*
ESP32가 수면에서 깨어나는 원인을 출력하는 함수
*/
void print_wakeup_reason(){
  esp_sleep_wakeup_cause_t wakeup_reason;

  wakeup_reason = esp_sleep_get_wakeup_cause();

  switch(wakeup_reason)
  {
    case ESP_SLEEP_WAKEUP_EXT0 : Serial.println("Wakeup caused by external signal using RTC_IO"); break;
    case ESP_SLEEP_WAKEUP_EXT1 : Serial.println("Wakeup caused by external signal using RTC_CNTL"); break;
    case ESP_SLEEP_WAKEUP_TIMER : Serial.println("Wakeup caused by timer"); break;
    case ESP_SLEEP_WAKEUP_TOUCHPAD : Serial.println("Wakeup caused by touchpad"); break;
    case ESP_SLEEP_WAKEUP_ULP : Serial.println("Wakeup caused by ULP program"); break;
    default : Serial.printf("Wakeup was not caused by deep sleep: %d\n", wakeup_reason); break;
  }
}

void setup(){
  Serial.begin(115200);
  delay(1000); // Serial 모니터를 열기 위해 잠시 대기합니다.

  // 부트 번호를 증가시키고 매 재부팅 시 출력합니다.
  ++bootCount;
  Serial.println("부트 번호: " + String(bootCount));

  // ESP32의 깨어나는 원인을 출력합니다.
  print_wakeup_reason();

  /*
  먼저 웨이크업 소스를 구성합니다.
  ESP32가 매 5초마다 깨우도록 설정합니다.
  */
  esp_sleep_enable_timer_wakeup(TIME_TO_SLEEP * uS_TO_S_FACTOR);
  Serial.println("Setup ESP32 to sleep for every " + String(TIME_TO_SLEEP) +
  " Seconds");

  /*
  이제 모든 주변 장치의 전원을 끄거나 켜둘지를 결정합니다.
  기본적으로 ESP32는 웨이크업 소스에 필요하지 않은 주변 장치의
  전원을 자동으로 차단하지만, 전력 사용자라면 
  이 부분이 유용할 것입니다. API 문서에서 자세히 읽어보세요.
  http://esp-idf.readthedocs.io/en/latest/api-reference/system/deep_sleep.html
  아래의 줄은 딥 슬립에서 모든 RTC 주변 장치를 끄도록 설정합니다.
  */
  //esp_deep_sleep_pd_config(ESP_PD_DOMAIN_RTC_PERIPH, ESP_PD_OPTION_OFF);
  //Serial.println("Configured all RTC Peripherals to be powered down in sleep");

  /*
  이제 웨이크 원인을 설정했으며 필요하다면
  딥 슬립 중 주변 장치 상태를 설정했으므로,
  이제 딥 슬립 모드로 들어갑니다.
  웨이크업 소스가 제공되지 않았지만 딥 슬립이 시작되면,
  하드웨어 리셋이 발생할 때까지 무한정 잠들게 됩니다.
  */
  Serial.println("Going to sleep now");
  delay(1000);
  Serial.flush(); 
  esp_deep_sleep_start();
  Serial.println("This will never be printed");
}

void loop(){
  // 이 함수는 호출되지 않습니다.
}

 

 

코드설명

수면 시간 정의

ESP32가 수면에 들어갈 기간을 정의합니다.

#define uS_TO_S_FACTOR 1000000  /* 마이크로초를 초로 변환하기 위한 변환 계수 */
#define TIME_TO_SLEEP  5        /* ESP32가 수면 상태로 들어가는 시간 (초 단위) */
 

마이크로초를 초로 변환하기 위해 uS_TO_S_FACTOR 변수를 정의하고, 수면 기간을 5초로 설정했습니다.

RTC_DATA_ATTR  메모리 속성

RTC_DATA_ATTR를 사용하여 부트 카운트를 정의합니다. 이 메모리 속성을 사용하면 ESP32가 다시 시작되더라도 이 데이터는 메모리에 유지됩니다.

RTC_DATA_ATTR int bootCount = 0;

 

 

bootCount 변수는 부트할 때마다 1씩 증가합니다.  Serial Monitor에 출력합니다.

 

깨어나는 이유

print_wakeup_reason()는 잠에서 깨어나게 한 원인을 출력하는 함수입니다.

void print_wakeup_reason() {
  esp_sleep_wakeup_cause_t wakeup_reason;

  wakeup_reason = esp_sleep_get_wakeup_cause();

  switch (wakeup_reason) {
    case ESP_SLEEP_WAKEUP_EXT0:     Serial.println("Wakeup caused by external signal using RTC_IO"); break;
    case ESP_SLEEP_WAKEUP_EXT1:     Serial.println("Wakeup caused by external signal using RTC_CNTL"); break;
    case ESP_SLEEP_WAKEUP_TIMER:    Serial.println("Wakeup caused by timer"); break;
    case ESP_SLEEP_WAKEUP_TOUCHPAD: Serial.println("Wakeup caused by touchpad"); break;
    case ESP_SLEEP_WAKEUP_ULP:      Serial.println("Wakeup caused by ULP program"); break;
    default:                        Serial.printf("Wakeup was not caused by deep sleep: %d\n", wakeup_reason); break;
  }
}

setup() 함수

다음과 같이 구성됩니다.

  • Serial 포트를 초기화하고 1초간 대기한 후 부트 카운트를 증가시킵니다.
  • print_wakeup_reason() 메서드를 사용하여 ESP32가 수면에서 깨어난 이유를 출력합니다.
  • ESP32가 5초마다 깨우도록 타이머를 구성합니다.
  • Serial 포트로 수면에 들어가겠다는 메시지를 출력하고, ESP32를 수면 상태로 전환합니다.
void setup(){
  Serial.begin(115200);
  delay(1000); // Serial 모니터를 열기 위해 잠시 대기합니다.

  // 부트 번호를 증가시키고 매 재부팅 시 출력합니다.
  ++bootCount;
  Serial.println("부트 번호: " + String(bootCount));

  // ESP32의 깨어나는 원인을 출력합니다.
  print_wakeup_reason();

  /*
  먼저 웨이크업 소스를 구성합니다.
  ESP32가 매 5초마다 깨우도록 설정합니다.
  */
  esp_sleep_enable_timer_wakeup(TIME_TO_SLEEP * uS_TO_S_FACTOR);
  Serial.println("Setup ESP32 to sleep for every " + String(TIME_TO_SLEEP) +
  " Seconds");

  Serial.println("Going to sleep now");
  delay(1000);
  Serial.flush(); 
  esp_deep_sleep_start();
  Serial.println("This will never be printed");
}

테스트

코드를 업로드한 후 Serial Monitor를 열고 보드가 수면 상태에 들어가고 다시 깨워질 때 Serial Monitor의 출력 결과를 확인하세요. 이 출력을 통해 타이머 웨이크업의 작동을 확인할 수 있습니다.