'FTDI'에 해당되는 글 22건

  1. 2021.02.02 Hardware | ESP-12 사용기 6
  2. 2021.01.08 Hardware | ESP-07 사용기 2
  3. 2020.08.17 Hardware | ESP-03 사용기
  4. 2020.04.21 Hardware | ESP32 NTP Server 이용한 시간 맞추기
  5. 2020.04.18 Hardware | ESP32 Deep sleep 알아보기
  6. 2020.04.16 Hardware | ESP32 Cryptographic HW 가속 확인해 보기 2
  7. 2020.04.11 Hardware | EPS32 PWM 기능 확인해 보기
  8. 2020.04.09 Hardware | ESP32 의 internal sensor 확인해 보기 2
  9. 2020.04.08 Hardware | ESP32 의 Dual core 확인해 보기
  10. 2020.03.23 Hardware | ESP32 스펙 확인해 보기

Hardware | ESP-12 사용기

|

ESP-01 부터 시작한 ESP8266 시리즈 중, 이번에는 ESP-12 사용기 입니다.


* Hardware | ESP-07 사용기

https://chocoball.tistory.com/entry/Hardware-ESP07-using


* Hardware | ESP-03 사용기

https://chocoball.tistory.com/entry/Hardware-ESP03-using


* Hardware | ESP-01 or ESP8266 사용기 - 5

https://chocoball.tistory.com/entry/Hardware-ESP01-or-ESP8266-using-5


* Hardware | ESP-01 or ESP8266 사용기 - 4

https://chocoball.tistory.com/entry/Hardware-ESP01-or-ESP8266-using-4


* Hardware | ESP-01 or ESP8266 사용기 - 3

https://chocoball.tistory.com/entry/Hardware-ESP01-or-ESP8266-using-3


* Hardware | ESP-01 or ESP8266 사용기 - 2

https://chocoball.tistory.com/entry/Hardware-ESP01-or-ESP8266-using-2


* Hardware | ESP-01 or ESP8266 사용기 - 1

https://chocoball.tistory.com/entry/Hardware-ESP01-or-ESP8266-using-1




1. 구입


일전에 구입한 ESP-07 와 동일한 업자에게서 구입.


* ESP8266 ESP-01 ESP-01S ESP-07 ESP-12E ESP-12F remote serial Port WIFI wireless module intelligent housing system Adapter 2.4G

https://www.aliexpress.com/item/32339917567.html



도착 샷.



Pinout 정보가 새겨진 뒷면.





2. Pinout


ESP8266EX 칩을 충분히 활용할 수 있는 Pinout 구성으로 되어 있습니다.





3. Breakout 보드


중간의 0 ohm 을 제거해 주면, 뒷 면의 Voltage Regulator 를 사용할 수 있게 됩니다.

이는 ESP-07 에서도 다루었던 내용이라, 자세한 내용은 생략합니다.





4. Diagram


Programming (Flashing) 하는 연결도와 Normal (구동) 하기 위한 연결도는 다릅니다. 아래 사이트에서 정보를 얻었습니다.


* Programming ESP8266 ESP-12

https://www.instructables.com/Programming-ESP8266-ESP-12/



* Programming Mode


Flash 메모리에 새로은 firmware 나 source 를 올리기 위한 mode 입니다.

차이는 IO0 / 18 번 pin 을 pull-up 해주냐 마냐의 차이.



* Normal Use Mode (after Upload)


Flash chip 에 업로드한 프로그램을 실행시키기 위한 모드 입니다.


위의 Programming 모드와 Normal 모드를 결합한 연결 구성 입니다.

이 Programming mode 로 진입하기 위해서는, 스위치 버튼 눌러주면서 전원을 on 하면 됩니다.



실제 구성 사진은 다음과 같습니다.


사실은 Breakout 보드에 ESP-12 를 결합해 놨으므로, Breakout 보드상에 이미 장착된 저항을 이용하면, 추가로 저항 2개만 필요합니다.

위 / 아래 연결 구성은 Breakout 보드가 없을 때의 모습이지만, 필요한 Pin 에 Voltage/Ground 가 연결되어 있으므로 문제 없이 동작합니다.



ESP2866 계열에서는 그나마 끝판왕인 ESP-12 가 연결된 모습.





5. 기본 확인


기본으로 올려진 Firmware version 과 몇 가지 명령어 시험.

기본 버전은 2016년1.3.0.0 이군요.



AT+RST 를 이용하여 rebooting. 사용된 Flash Chip 정보를 알 수 있습니다. QIO 모드이면서 32Mbit (512KB+512KB) 라고 나옵니다.

32Mbit1024KB+1024KB 일 듯 한데... 일단 넘어 갑니다.



Internet 에 연결하여 AT+CIUPDATE 실행을 통하여 원격 update 를 시도해 봤으나, ERROR 를 냅니다. 역시나 옛날 버전.



Flash Chip 은 QUAD : 32Mbit 로 문제 없이 확인 됩니다.





6. Programming


일단은 문제가 없는 듯 하니, source 를 올려 봅니다. 테스트 해볼 소스는 BlinkCheckFlashConfig.



CheckFlashConfig 소스는 다음과 같습니다.


/*
  ESP8266 CheckFlashConfig by Markus Sattler

  This sketch tests if the EEPROM settings of the IDE match to the Hardware
*/

void setup(void) {
  Serial.begin(115200);
}

void loop() {

  uint32_t realSize = ESP.getFlashChipRealSize();
  uint32_t ideSize = ESP.getFlashChipSize();
  FlashMode_t ideMode = ESP.getFlashChipMode();

  Serial.printf("Flash real id:   %08X\n", ESP.getFlashChipId());
  Serial.printf("Flash real size: %u bytes\n\n", realSize);

  Serial.printf("Flash ide  size: %u bytes\n", ideSize);
  Serial.printf("Flash ide speed: %u Hz\n", ESP.getFlashChipSpeed());
  Serial.printf("Flash ide mode:  %s\n", (ideMode == FM_QIO ? "QIO" : ideMode == FM_QOUT ? "QOUT" : ideMode == FM_DIO ? "DIO" : ideMode == FM_DOUT ? "DOUT" : "UNKNOWN"));

  if (ideSize != realSize) {
    Serial.println("Flash Chip configuration wrong!\n");
  } else {
    Serial.println("Flash Chip configuration ok.\n");
  }

  delay(5000);
}


QIO4MiB 네요. 지금까지 완성품을 구입한 ESP8266 계열에서는 가장 좋은 Flash Chip 을 사용한 모듈 입니다.



소스가 업로드 되는 과정에 있어서도 문제 없습니다. 순탄한 흐름.


esptool.py v2.8
Serial port COM3
Connecting....
Chip is ESP8266EX
Features: WiFi
Crystal is 26MHz
MAC: 50:02:91:78:d3:60
Uploading stub...
Running stub...
Stub running...
Configuring flash size...
Auto-detected Flash size: 4MB
Compressed 267104 bytes to 196785...
Wrote 267104 bytes (196785 compressed) at 0x00000000 in 17.5 seconds (effective 122.3 kbit/s)...
Hash of data verified.

Leaving...
Hard resetting via RTS pin...


보드상에 장착된 LED 를 깜빡이는 소스 입니다.


/*
  ESP8266 Blink by Simon Peter
  Blink the blue LED on the ESP-01 module
  This example code is in the public domain

  The blue LED on the ESP-01 module is connected to GPIO1
  (which is also the TXD pin; so we cannot use Serial.print() at the same time)

  Note that this sketch uses LED_BUILTIN to find the pin with the internal LED
*/

void setup() {
  pinMode(LED_BUILTIN, OUTPUT);     // Initialize the LED_BUILTIN pin as an output
}

// the loop function runs over and over again forever
void loop() {
  digitalWrite(LED_BUILTIN, LOW);   // Turn the LED on (Note that LOW is the voltage level
  // but actually the LED is on; this is because
  // it is active low on the ESP-01)
  delay(1000);                      // Wait for a second
  digitalWrite(LED_BUILTIN, HIGH);  // Turn the LED off by making the voltage HIGH
  delay(2000);                      // Wait for two seconds (to demonstrate the active low LED)
}


예상한 것과 달리 문제 없이 동작.



지금까지 ESP8266 가지고 놀았던 과정 중, 전혀 문제 없이 여기까지 왔습니다.

ESP8266 을 Flashing 하는 작업은 이제 통달 한 듯 한 느낌.




7. Firmware Update


최신 firmware 를 사용합니다. 2020년에 공개된 Non-OS SDK 3.0.4 를 이용합니다.


ESP8266_NONOS_SDK-3.0.4.zip



Firmware upload 에 필요한 BIN 파일 및 Address 는, 최신 문서에 잘 나와 있습니다.

4a-esp8266_at_instruction_set_en.pdf



32 Mbit (4 MiB) 버전이므로, 아래 section 을 찾아 BIN / Address 정보를 그대로 사용합니다.


---------------------------------------------------------------------------------------------
|               BIN             | Address  |                 Description                    |
---------------------------------------------------------------------------------------------
| boot_v1.7.bin                 | 0x00000  | In /bin/at.                                    |
---------------------------------------------------------------------------------------------
| user1.2048.new.5.bin          | 0x01000  | In /bin/at/1024+1024.                          |
---------------------------------------------------------------------------------------------
| blank.bin                     | 0x3FB000 | Initializes RF_CAL parameter area.             |
---------------------------------------------------------------------------------------------
| esp_init_data_default_v08.bin | 0x3FC000 | Stores default RF parameter values,            |
|                               |          | has to be downloaded into flash at least once. |
|                               |          | If the RF_CAL parameter area is initialized,   |
|                               |          | this bin has to be downloaded too.             |
---------------------------------------------------------------------------------------------
| blank.bin                     | 0xFE000  | Initializes Flash user parameter area,         |
|                               |          | more details in Appendix.                      |
---------------------------------------------------------------------------------------------
| blank.bin                     | 0x3FE000 | Initializes Flash system parameter area,       |
|                               |          | more details in Appendix.                      |
---------------------------------------------------------------------------------------------


Flash chip 용량이 크고, SPI Mode 도 빠르기 때문에, 1024 KB + 1024 KB (32 Mbit-C1) 버전으로 입혀 봅니다.



별다른 문제 없이 성공. 최신 버전인 AT - 1.7.4 / SDK - 3.0.4 가 올라 갔습니다.




AT+RST 를 이용하여 rebooting sequence 를 보면, QIO / 32Mbit(1024KB+1024KB) 로 잘 동작 합니다.



참고로, "SpiAutoSet" 을 키고 업로드 하면, 강제로 32Mbit 으로 변경됩니다.



1024 KB + 1024 KB (32 Mbit-C1) 버전용 BIN / Address 를 사용하고 있으므로, 메뉴얼로 32Mbit-C1 을 선택해 줘야 합니다.




8. AT Command 확인


Internet 접속 및 전번적인 확인 작업. 특별히 문제 없슴.


* AT+CWMODE_CUR : Sets the Current Wi-Fi mode; Configuration Not Saved in the Flash

- 1: Station mode

- 2: SoftAP mode

- 3: SoftAP+Station mode


* AT+CWLAP : Lists Available APs


* AT+CWJAP_CUR : Connects to an AP; Configuration Not Saved in the Flash


* AT+CIFSR : Gets the local IP address


* AT+PING="www.google.com" : Ping packets




* AT+CIPSTATUS : Gets the connection status


* AT+CIPBUFSTATUS : Checks the status of TCP-send-buffer


* AT+CWQAP : Disconnects from the AP


AP 와 연결을 끊으면, internet 연결 정보가 깔끔하게 reset 되지 않고 일정 시간동안 남아 있습니다.

시간이 지나고 다시 확인하면 reset 되어 있슴.




* AT+CIUPDATE : Upgrades the software through network


역시 최신 firmware 라 그런지, FOTA - 인터넷을 통한 firmware update 가 가능합니다.



Firmware update 하면서 LED 가 깜빡거리는 모습이 좋아, 동영상으로 담아 봤습니다.




* AT+RESTORE : Restores the Factory Default Settings



모든 확인이 끝났습니다. 앞으로 sensor 들과 같이 활용할 기회에 사용하면 되겠네요.




FIN


중국 제조사 답게 WeChat 관련한 옵션이 새로 추가되었습니다.



And

Hardware | ESP-07 사용기

|

ESP8266 시리즈를 사용해 보면서, ESP-01 부터 시작하여 ESP-03 을 사용해 보았습니다.


* Hardware | ESP-03 사용기

https://chocoball.tistory.com/entry/Hardware-ESP03-using


* Hardware | ESP-01 or ESP8266 사용기 - 5

https://chocoball.tistory.com/entry/Hardware-ESP01-or-ESP8266-using-5


* Hardware | ESP-01 or ESP8266 사용기 - 4

https://chocoball.tistory.com/entry/Hardware-ESP01-or-ESP8266-using-4


* Hardware | ESP-01 or ESP8266 사용기 - 3

https://chocoball.tistory.com/entry/Hardware-ESP01-or-ESP8266-using-3


* Hardware | ESP-01 or ESP8266 사용기 - 2

https://chocoball.tistory.com/entry/Hardware-ESP01-or-ESP8266-using-2


* Hardware | ESP-01 or ESP8266 사용기 - 1

https://chocoball.tistory.com/entry/Hardware-ESP01-or-ESP8266-using-1


이번에는 ESP-07 입니다.




1. 구입


아래 AliExpress 링크에서 구입 했습니다.

ESP-12 도 함께 구입 했으니, 이 글 다음에는 ESP-12 에 대해서도 다뤄 보도록 하겠습니다.


* ESP8266 ESP-01 ESP-01S ESP-07 ESP-12E ESP-12F remote serial Port WIFI wireless module intelligent housing system Adapter 2.4G

https://www.aliexpress.com/item/32339917567.html



도착 샷. 깡통 쉴드로 전자파 차폐가 되어 있습니다.



PCB 밑부분은 IO Pin 정보가 기재되어 있습니다.

제조는 DOITING 이라는 회사인 듯 한데, PCB 는 AI-Thinker 로 보이네요. 설계가 동일한지라 완전 짬뽕.



Pinout 정보 입니다.





2. Breakout Board


ESP-03 때도 사용 했었지만, EPS-07 / ESP-12 도 Breakout 보드에 올렸습니다.

이 Breakout 보드가 없으면, 2.54mm 의 Pin 간격이 맞지 않아 빵판에서 그 대로 사용할 수 없게 되어 있습니다.



주의해야 할 사항으로는, Voltage Regulator 를 추가로 장착시에는 중간에 보이는 "0" resistor 를 제거해야 정상 동작 됩니다.


* Adding Wi-Fi telemetry to the Pixhawk flight controller with an ESP8266 module

https://rays-blog.de/2016/10/21/224/adding-wi-fi-telemetry-to-pixhawk-flight-controller-with-esp8266-module/



혹시 모를 전압 문제를 방지하고자, Voltage Regulator 를 장착 했습니다.

사실 3.3V 만 제대로 넣어 주면 상관 없는 것이긴 한데, 기판에 활용을 할 수 있게 해 놨으니 사용해 봅니다.


5V 를 인가하면, 3.3V 로 바꿔서 ESP-07 에 전압을 인가해 줍니다.



중간에 보이는 "0" ohm 저항은 이쁘게 제거.



그 위에 ESP-07 을 얹어 줍니다.



CH_PC 을 측정해 보면, 자동으로 전압이 Pull-down 되어 있는 것을 알 수 있습니다.





3. Diagram


Pinout 정보를 기반으로 연결해 보면 아래와 같이 됩니다.



다만, Breakout 보드에 Voltage Regulator 이외에, 필요한 Pull-down 저항이 구비되어 있으니, 연결은 좀 더 간단하게 할 수 있습니다.


* How to prepare your ESP8266 (ESP-12) for flashing

https://www.sensate.io/tutorial-how-to-prepare-your-esp8266-esp-12-for-flashing


아래는 Breakout 보드가 없는 경우의 생 연결도 입니다.




아래는 Breakout 보드를 사용 했을 때의 연결도 입니다. (저의 경우)



Breakout 보드가 있더라도 Breakout 보가 없는 연결 방법을 해도 문제는 없으나,

이왕이면 정식 + 간단한 방법인 연결을 사용하면 되겠습니다.



실제 연결 모습은 아래와 같습니다.





4. 기본 Firmware 확인


기본 firmware 이 장착된 상태 이니, 어떤 version 인지 확인해 봅니다.

1.1.0.0 이고, 2016년 병신년 버전이네요.



AT+RST 하면, 보통 Flash Chip 정보도 나옵니다만, 예전 버전이라서 그런지 그딴거 없습니다.



Internet 연결 후, AT+CIUPDATE 를 해봐도 ERROR 만 반겨 줍니다.





5. 삽질의 향연


새로운 Firmware 를 올리고 시험해 봤으나, 아래와 같이 err 만 내 뱉습니다.

또한, BAUD Rate 가 74880 baud 의 변태적인 설정에서만 문자가 보이는 것이 맘에 들지 않더군요.



ESP8266 DOWNLOAD TOOL 에서 ERASE 후, firmware 올려도 동일한 현상입니다.




* 문제 1 : 적절한 Board 선택


첫 번째 문제는, Flash Chip 확인 위한 소스를 올릴 때, Generic ESP8266 Module 이 아니라,

먼저 테스트 했던 ESP-12 Module 용으로 설정 했던 것이 원인이었습니다.


ESP-12 용으로 소스가 입혀지다 보니, memory address 의 시작 지점부터 꼬였었던 것이 아닌가 추측해 봅니다.




* 문제 2 : 적절한 Flash Chip 의 SPI Mode 선택


Flash ChipSPI Mode 가 Q 로 시작하는 QIO / QOUT 으로 설정한 것이 문제였습니다.



Flash Chip 은, ESP8266 DOWNLOAD TOOL 에서 "SpiAutoSet" 을 이용하여 자동 인식을 사용하면 QUAD 로 인식됩니다.

그리하여, 비슷한 QIO 또는 QOUT 로 설정하면 될 것 같으나, 사실은 DOUT 로 설정해야 정상 동작 합니다.


정상적일 때, Flash Chip 인식 소스를 이용하여 확인해 봐도, DOUT 으로 확인이 가능합니다.


File > Examples > ESP8266 > CheckFlashConfig


/*
  ESP8266 CheckFlashConfig by Markus Sattler

  This sketch tests if the EEPROM settings of the IDE match to the Hardware
*/

void setup(void) {
  Serial.begin(115200);
}

void loop() {

  uint32_t realSize = ESP.getFlashChipRealSize();
  uint32_t ideSize = ESP.getFlashChipSize();
  FlashMode_t ideMode = ESP.getFlashChipMode();

  Serial.printf("Flash real id:   %08X\n", ESP.getFlashChipId());
  Serial.printf("Flash real size: %u bytes\n\n", realSize);

  Serial.printf("Flash ide  size: %u bytes\n", ideSize);
  Serial.printf("Flash ide speed: %u Hz\n", ESP.getFlashChipSpeed());
  Serial.printf("Flash ide mode:  %s\n", (ideMode == FM_QIO ? "QIO" : ideMode == FM_QOUT ? "QOUT" : ideMode == FM_DIO ? "DIO" : ideMode == FM_DOUT ? "DOUT" : "UNKNOWN"));

  if (ideSize != realSize) {
    Serial.println("Flash Chip configuration wrong!\n");
  } else {
    Serial.println("Flash Chip configuration ok.\n");
  }

  delay(5000);
}


DOITING 사의 원가 절감이나, Fake Chip 을 이용한 Flash 메모리 구성이 이런 결과를 초래한 것 같습니다.





6. Firmware 최신


하루 동안의 삽질을 끝내고, 겨우 최신 firmware 로 업데이트가 가능 했습니다.

아래 사이트에서 최신 버전의 firmware 를 다운로드 받습니다.


* ESPRESSIF

https://www.espressif.com/

ESP8266_NONOS_SDK-3.0.4.zip


2021년 1월 기준, V3.0.4 가 최신입니다.



관련 문서를 보면, 8 Mbit = 1MiB Flash 를 update 와 관련한 address 와 해당 파일에 잘 나와 있습니다.


4a-esp8266_at_instruction_set_en.pdf



사용될 파일과 Address 정보는 다음과 같습니다.


---------------------------------------------------------------------------------------------
|               BIN             | Address  |                 Description                    |
---------------------------------------------------------------------------------------------
| boot_v1.7.bin                 | 0x00000  | In /bin/at.                                    |
---------------------------------------------------------------------------------------------
| user1.2048.new.2.bin          | 0x01000  | In /bin/at/512+512.                            |
---------------------------------------------------------------------------------------------
| blank.bin                     | 0xFB000  | Initializes RF_CAL parameter area.             |
---------------------------------------------------------------------------------------------
| esp_init_data_default_v08.bin | 0xFC000  | Stores default RF parameter values,            |
|                               |          | has to be downloaded into flash at least once. |
|                               |          | If the RF_CAL parameter area is initialized,   |
|                               |          | this bin has to be downloaded too.             |
---------------------------------------------------------------------------------------------
| blank.bin                     | 0x7E000  | Initializes Flash user parameter area,         |
|                               |          | more details in Appendix.                      |
---------------------------------------------------------------------------------------------
| blank.bin                     | 0x3FE000 | Initializes Flash system parameter area,       |
|                               |          | more details in Appendix.                      |
---------------------------------------------------------------------------------------------


ESP8266 Download Tool 을 이용하여 Flashing 합니다.



짜잔~~ 최신 버전으로 update 되었습니다.





7. 최신 Firmware 확인


AT+RST 를 통해 booting sequence 를 확인해 봅니다.

SPI ModeDOUT 이며, 8Mbit (512KB+512KB) 버전이라는 것을 알 수 있습니다.



Internet 연결을 위한 AT 명령어들을 차례로 확인해 봅니다.


AT+CWMODE_CUR=3 : Sets the Current Wi-Fi mode. Configuration Not Saved in the Flash.

-- 1: Station mode

-- 2: SoftAP mode

-- 3: SoftAP+Station mode


AT+CWLAP : Lists Available APs


* AT+CWJAP_CUR : Connects to an AP; Configuration Not Saved in the Flash


* AT+CIFSR : Gets the local IP address


* AT+PING="www.google.com" : Ping packets



* AT+CIPSTATUS : Gets the connection status


* AT+CIPBUFSTATUS : Checks the status of TCP-send-buffer




* AT+CIUPDATE : Upgrades the software through network


최신버전이라서 그런지, 인터넷을 통한 업데이트도 잘 됩니다.

신기한건, 분명 동일한 소스인데, 이렇게 인터넷을 통해 업데이트 하면 compile time 이 3초 (17초에서 20초로 변경) 정도 차이 납니다.

또한, jump to run user2 @ 81000 이라고 뜨면서, user 와 그 뒤의 숫자가 변경됩니다. 아마 모드가 바뀌면서 그런 듯.



* AT+RESTORE : Restores the Factory Default Settings


RESTORE 를 사용하면, 공장 초기화 및 rebooting 을 합니다.



궁금하여, AT+CIUPDATE 를 한번 더 했더니만, user 와 숫자가 원래 대로 되돌아 왔습니다.

Running 과 Control 모드, 두 개가 각각 번갈아 가면서, 동작을 관장 하는 것 같네요.



참고로, AT+CIUPDATE 동작하는 동영상을 올립니다. 다운로드 > Flashing > rebooting 의 일련의 과정이 한 번에 일어납니다.





8. Source 확인


Blink 소스를 올려 봤습니다.


File > Examples > ESP8266 > Blink


/*
  ESP8266 Blink by Simon Peter
  Blink the blue LED on the ESP-01 module
  This example code is in the public domain

  The blue LED on the ESP-01 module is connected to GPIO1
  (which is also the TXD pin; so we cannot use Serial.print() at the same time)

  Note that this sketch uses LED_BUILTIN to find the pin with the internal LED
*/

void setup() {
  pinMode(LED_BUILTIN, OUTPUT);     // Initialize the LED_BUILTIN pin as an output
}

// the loop function runs over and over again forever
void loop() {
  digitalWrite(LED_BUILTIN, LOW);   // Turn the LED on (Note that LOW is the voltage level
  // but actually the LED is on; this is because
  // it is active low on the ESP-01)
  delay(1000);                      // Wait for a second
  digitalWrite(LED_BUILTIN, HIGH);  // Turn the LED off by making the voltage HIGH
  delay(2000);                      // Wait for two seconds (to demonstrate the active low LED)
}


이쁘게 잘 동작 합니다.



FIN


And

Hardware | ESP-03 사용기

|

ESP8266 을 사용하면서 GPIO 핀이 많은 모듈이 필요해 졌습니다.


기존 ESP-01 은 arduino 와 연결하여 WiFi 부분을 커버하는 것 외에 sensor 로부터 값을 입력 받을 수 있는 추가 Pin 이 없습니다.

포름알데히드 센서를 이용해 보면서, ESP-01 말고 GPIO 핀이 많은 것을 찾게 되었습니다.


* Hardware | ZE08-CH2O Formaldehyde 센서 사용해보기

https://chocoball.tistory.com/entry/Hardware-ZE08-CH2O-Formaldehyde-sensor-using




1. ESP-01


처음엔 몰랐지만, ESP2866 이라는 것은 ESP-01 만 뜻하는 것이 아니라, ESP8266EX 을 사용한 WiFi module 의 총칭이었던 것입니다.

지금까지 ESP8266 = ESP-01 로 알고, 입출력 Pin 이 더 필요한 경우, SoftwareSerial 을 어떻게 처리해야 하는지 히고 있었습니다.



위의 도식처럼 ESP8266EX 는, 많은 GPIO 를 지원하고 있었습니다.


단순히, ESP-01 의 pin out 갯수가 적었던 것이였죠. 더 많은 연결을 위해 ESP-01 도 pin out 을 처음부터 늘려 줬으면 어떠했을까 합니다.

어떤 사람이 "it's a shame to have such a small number of GPIOs at ESP-01" 라고 쓴 글을 본것 같습니다.


ESP8266EX chip 의 가느다란 다리에 직접 선을 납땜하면 사용할 수 있습니다. 시도해 봅니다.



실패.




2. ESP-03


ESP8266EX 를 사용하면서 GPIO 핀을 활용할 수 있는 breakout 보드들이 존재 했었습니다. ESP-03 / ESP-07 / ESP-12 등등...

ESP32 를 쓰면 쉽게 문제 해결 되지만, 굳이 어려운 방법으로 도전해 보기로 합니다.


우선 ESP-03 만 보더라도 GPIO 가 8개나 Pinout 으로 구성되어 있습니다.



자세한 Pinout 정보 입니다.



참고로, RST pinout 은 따로 구비되어 있지 않고, 아래 사진처럼 보드 위에 마련되어 있습니다.

Program 을 입힐 때, RST 가 있으면 편하나, 전원을 껐다 키면서 IO 0 (HIGH Run, LOW Flash) 핀을 이용하여 되니, 사용하지 않기로 합니다.


사용 전력을 아끼는 Sleep mode 구현시에는 필요하다 하나, 지금은 필요 없으니 그냥 놔두기로 합니다.



우선 ESP-03 을 구입.


* 1PC ESP8266 serial WIFI model ESP-03 Authenticity Guaranteed esp03 for arduino

https://www.aliexpress.com/item/32641401163.html



잊어먹고 있으니, 어느새 도착.



ESP8266EX 메인 칩과, 25Q40CT 라고 쓰인 Flash memory 가 보입니다.



사용된 오실레이터는 26MHz 입니다.





3. 어뎁터 보드 구매


ESP-03 의 Pin 들은, 빵판에 바로 연결할 수 있는 2.54mm 간격이 아니고, pin 들 사이가 더 조밀합니다.

이를 해결하기 위해, 자가로 pin header 를 붙일 수도 있고, 직접 선을 연결할 수 있으나 지저분해 집니다.


원래는 ESP-07 / ESP-12 용으로 나와 있는 어뎁터가 있는데, 잘만 하면 맞을 것 같더군요.

어차피 ESP-07 / ESP-12 구매하면 필요할 듯 하여, 5개가 한 묶음인 아래 어뎁터 보드도 구매합니다.


* 5pcs/lot ESP8266 serial WIFI Module Adapter Plate Applies to ESP-07, ESP-12F, ESP-12E

https://www.aliexpress.com/item/32971304797.html



잊을만 하니 도착.



양쪽에 male pin header 를 연결할 수 있게 되어 있고, ESP-07 / ESP-12 pin 과 맞닿는 부분을 납땜하게 되어 있습니다.



ESP-03 을 얹어 보니, 납땜 부위와 간격이 많이 떨어져 있으나, 납물을 길게 연결하여, 어찌어찌 연결할 수 있을 것 같습니다.





4. ESP-03 을 어뎁터 보드에 납땜


친절하게도 전원 관련된 저항이 어뎁터에 이미 실장되어 있습니다.



뒷면에는 3.3V 용 레귤레이터 자리도 마련되어 있습니다. 전압이 over shoot 나지 않게 안정적인 전원 공급을 위해 있으면 좋은 것이죠.



마침 3.3V regulator 가 있으니 붙여 줍니다.



원래는 ESP-07 / ESP-12 를 위한 저항과 레귤레이터 회로겠으나, 아래를 참고하면서 ESP-03 에서도 활용할 수 있는지 확인해 봅니다.


* MY METHOD FOR BREADBOARDING AN ESP-03

https://www.esp8266.com/viewtopic.php?p=18369



일반 사용 모드와, flashing 모드를 위해서는 push switch 도 붙여야겠네요.



확인에 또 확인하고 아래와 같이 만들어 봤습니다.



실패...


저항이고 레귤레이터고, 스위치고 점퍼고 다 제거했습니다. 단순하게 사용하는게 최고 입니다.

납땜은 아래처럼 길게 늘여뜨리면, 이 어뎁터를 ESP-03 용으로 사용 가능합니다.





5. Flash memory 크기 확인


25Q40CT 라고 씌인 Flash memory 사양을 검색해 보니 대충 다음과 같은 사양입니다.


- GIGADEVICE [GigaDevice Semiconductor (Beijing) Inc.]

- GD25Q40CTEG : 3.3V Uniform Sector Dual and Quad Serial Flash

- GigaDevice Semiconductor (Beijing) Inc.

- 4M-bit (512K-byte)


GD25Q40C.PDF


4Mbit = 512KiB... 털썩.

FTDI 모듈과 TX/RX 를 연결하여 본격적으로 활용해 봅니다. ESP-03 의 연결 정보는 다음과 같습니다.



전원과 FTDI 그리고 flashing 을 위한 스위치 연결 구성은 다음과 같아요.

가능하면 전원 공급은 FTDI 를 통해서 얻는것 보다, 분리하는 것이 좋습니다.



실재 구현 모습입니다.



FTDI 를 이용하여 PC 에 연결해, 확인해 봅니다. 역시군요.



기본으로 입혀져 있는 firmware 는 AI-Thinker 의 Boot 모드인 듯 합니다.



ESP8266 library 를 인스톨 하면, 기본으로 제공되는 Flash Check 소스를 입혀 봅니다.


File > Examples > ESP8266 > CheckFlashConfig



Flash mode 를 위해, 달아 놓은 스위치를 누르면서 전원을 넣고, flashing 을 해 봅니다. 잘 flashing 되네요.



그렇습니다... 틀림없는 512KiB 네요.





6. firmware update


Flash memory 를 교체하여 용량을 늘릴 예정이지만, 512KiB 에 올릴 수 있는 firmware 를 찾아 봅니다.

찾는 와중에 알게된 용어 정리.


APIs of "ESP8266_RTOS_SDK" are same as "ESP8266_NONOS_SDK"


중국산 모듈에 가장 많이 쓰이는 AI-Thinker.


* Ai-thinker

- v0.9.5.2

https://wiki.aprbrother.com/en/Firmware_For_ESP8266.html



파일명에 9600 표시가 없는 firmware : one for 9600 baud rate

파일명에 9600 표시가 없는 firmware : one for 115200 baud rate




* Updating ESP8266 Firmware

https://os.mbed.com/users/sschocke/code/WiFiLamp/wiki/Updating-ESP8266-Firmware

ESP8266_RTOS_SDK_v1.1_512kb.zip


Firmware 파일 못지 않게 중요한 address 정보.


---------------------------------------
|             BIN           | Address |
---------------------------------------
| boot_v1.1.bin             | 0x00000 |
| user1.bin                 | 0x01000 |
| esp_init_data_default.bin | 0x7C000 |
| blank.bin                 | 0x7E000 |
---------------------------------------


잘 동작함.




Espressif Systems (SDK V2.0.0 / AT V1.3)

4a-esp8266_at_instruction_set_en.pdf

esp8266_nonos_sdk_v2.0.0_16_08_10.zip


4Mbit = 512KiBSDK V2.0.0AT V1.3 이 올라간다고 메뉴얼에 적혀 있습니다만, 저는 되지 않더군요.




[SDK Release] ESP8266_NONOS_SDK_V1.4.0_15_09_18

https://bbs.espressif.com/viewtopic.php?f=46&t=1124

esp_iot_sdk_v1.4.0_15_09_18.zip


많은 firmware 를 테스트 하다 보니, 이 버전의 firmware update 후의 화면인지 기억이 잘... 여튼 성공 했었던것 같아요. 



Online 으로 firmware 를 업데이트 하는 FOTA 방식을 테스트 해봤습니다.

만, 마지막까지 문제 없이 진행되더니만 실패. Flash memory 용량이 적어 실패하는 듯. 





7. 32Mbit / 4MiB 로 업그레이드


우선 Flash chip 양쪽에 납을 충분히 먹이고 인두로 지지니 쉽게 떨어집니다. 무리해서 힘주지 않는게 포인트.



원래 실장되어 있던 flash memory 와 교체하려는 flash memory 크기만 비교해 봐도 꽤 다릅니다.



32Mbit Flash memory chip 을 납땜합니다. Oscillator 와 사이가 좁아서 힘들었습니다.



512KiB 칩은 조그마한 크기였는데, 4MiB 칩은 좀 큰 편이라, 기존 자리에 납땜 하려면 다리를 안쪽으로 구부려야 합니다.



ESP8266 DOWNLOAD TOOL 로 확인해 보니, 문제 없이 flash memory upgrade 가 완료 되었습니다.



구울 firmware 버전은 Non-OS 중에서 가장 최신 버전.


ESP8266_NonOS_AT_Bin_V1.7.4.zip



Flashing 할 때는, Address 를 정확히 따라야 합니다. V1.7.4 의 32Mbit (1024 KB + 1024 KB) 설정은 다음과 같습니다.



메뉴얼 대로 Address 잘 기입해서 flashing~!



문제 없이 booting 됩니다.



웃긴건, booting 할 때는 76,800 baud rate 로 동작하고 (위의 스샷에서 글씨가 깨지는 부분), 기본 모드에서는 115,200 baud 로 동작합니다.




8. WiFi 기능과 Sensor 값 입력을 동시에 수행


용량도 늘었으니, WiFi 기능을 사용하면서 sensor 값을 GPIO 14 으로 받아 internet 을 통해 값을 쏴주는 과정을, 아래 포스트에서 진행.


* Hardware | ZE08-CH2O Formaldehyde 센서 사용해보기

https://chocoball.tistory.com/entry/Hardware-ZE08-CH2O-Formaldehyde-sensor-using


Serial Monitor 에서 확인할 결과, GPIO 14 에서 입력 받은 값들도 정상적으로 확인.



인터넷을 통해서도 잘 값들이 전달됨도 확인 하였습니다. (자세한건 위의 포스트에서 확인 가능합니다.)





9. 추가 구매


이참에 ESP8266EX 시리즈를 추가로 구매 했습니다. 가지고 있는 ESP-01 이 납땜 실패로 사용할 수 없으니, ESP-01 도 추가 구매.


* ESP8266 ESP-01 ESP-01S ESP-07 ESP-12E ESP-12F remote serial Port WIFI wireless module intelligent housing system Adapter 2.4G
    - https://www.aliexpress.com/item/32339917567.html


ESP-01



언제 사용해 보겠냐며, ESP-07 도 구매.


ESP-07



ESP8266 chip 의 끝판왕 breakout 보드인 ESP-12F 도 구매.


ESP-12F



다음 포스팅 들은 ESP-07 / ESP-12F 에 대한 이야기가 되겠네요.


And

Hardware | ESP32 NTP Server 이용한 시간 맞추기

|

지금까지 ESP32 에 관한 글은 아래를 참고해 주세요.


* Hardware | ESP32 Deep sleep 알아보기
    - https://chocoball.tistory.com/entry/Hardware-ESP32-Deep-sleep

* Hardware | ESP32 Cryptographic HW 가속 확인해 보기
    - https://chocoball.tistory.com/entry/Hardware-ESP32-Cryptographic-HW-acceleration

* Hardware | EPS32 PWM 기능 확인해 보기
    - https://chocoball.tistory.com/entry/Hardware-EPS32-PWM

* Hardware | ESP32 의 internal sensor 확인해 보기
    - https://chocoball.tistory.com/entry/Hardware-ESP32-internal-sensors

* Hardware | ESP32 의 Dual core 확인해 보기
    - https://chocoball.tistory.com/entry/Hardware-ESP32-Dual-core

* Hardware | ESP32 스펙 확인해 보기
    - https://chocoball.tistory.com/entry/Hardware-ESP32-spec-check

* Hardware | ESP32 간단 사용기
    - https://chocoball.tistory.com/entry/Hardware-simple-review-ESP32


이 글을 마지막으로 ESP32 에 대해 대략적인 내용은 얼추 확인해 본 것 같습니다.

이후에는 WiFi 이용한 활용시에는 가능한 ESP32 를 사용해 보려 합니다.




1. NTP


본 포스트는 아래 글을 참조 하였습니다.


* Getting Date & Time From NTP Server With ESP32

- https://lastminuteengineers.com/esp32-ntp-server-date-time-tutorial/



NTP 서버란 인터넷에서 시간을 동기화 시켜주는 서버를 말합니다.
인증, GPS 위치와 연관된 시간 정보, 동기화와 관련된 timestamp 등, 인터넷 서비스의 거의 모든 기능들이 동일한 "시간" 정보가 필요합니다.


동일한 시간 기준으로 동작해야 하는 서비스를 위해, 인터넷에서는 NTP 라는 서비스가 지원되고 있습니다.


* Network Time Protocol

- https://en.wikipedia.org/wiki/Network_Time_Protocol


이를태면, 정확한 시간 정보를 가져올 수 있는 서버들이 존재한다는 것이죠.




2. WiFi



"인터넷" 을 통해 시간 정보를 가져와야 하므로, WiFi 등의 인터넷 연결이 필수 입니다.

ESP32 는, WiFi 연결을 위해 "WiFi.h" 라이브러리를 지원합니다. 이를 통해 쉽게 WiFi 연결을 실현해 줍니다.

지금까지 Arduino + ESP8266 에서는 AT command 를 이용하여, 하나하나 명령어를 정의해야 했었는데, 그럴 수고를 덜어줍니다.


const char* ssid       = "YOUR_SSID";
const char* password   = "YOUR_PASS";


인터넷 접속을 위한 WiFI SSID 및 비번 정의를 하면 끝 입니다. 정말로 이걸로 끝입니다.




3. NTP


NTP 서버를 통해 시간을 가져오는 소스는 다음과 같습니다.


#include "WiFi.h"
#include "time.h"

const char* ssid       = "YOUR_SSID";
const char* password   = "YOUR_PASS";

const char* ntpServer = "pool.ntp.org";
const long  gmtOffset_sec = 3600;
const int   daylightOffset_sec = 3600;

void printLocalTime() {
	struct tm timeinfo;
	if(!getLocalTime(&timeinfo)) {
		Serial.println("Failed to obtain time");
		return;
	}
	Serial.println(&timeinfo, "%A, %B %d %Y %H:%M:%S");
}

void setup() {
	Serial.begin(115200);
	
	// connect to WiFi
	Serial.printf("Connecting to %s ", ssid);
	WiFi.begin(ssid, password);
	while (WiFi.status() != WL_CONNECTED) {
		delay(500);
		Serial.print(".");
	}
	Serial.println(" CONNECTED");
	
	// init and get the time
	configTime(gmtOffset_sec, daylightOffset_sec, ntpServer);
	printLocalTime();
	
	// disconnect WiFi as it's no longer needed
	WiFi.disconnect(true);
	WiFi.mode(WIFI_OFF);
}

void loop() {
	delay(1000);
	printLocalTime();
}


위의 소스를 각 로컬 상황에 맞게 설정해줘야 합니다.


const char* ntpServer = "pool.ntp.org";
const long  gmtOffset_sec = 3600;
const int   daylightOffset_sec = 3600;


우선, NTP 서버는 "pool.ntp.org" 로 정의 합니다. 이 FQDN 을 통해 NTP 서버를 할당 받습니다.


"gmOffset_sec" 는 GMT 기준으로 얼마나 차이나는지를 확인합니다.

한국은 그리니치 천문대 기준 9시간 추가된 시간대인, "GMT+9" 이므로 "3600 * 9 = 32400" 만큼 더해주면 됩니다.


또한, "daylightOffset_sec" 은, 서머타임 적용 지역이면, 한시간인 3600 을 적용하면 됩니다.

우리나라는 서머타임 적용은 80년대에 일시적으로 적용하고, 그 이후 사용되지 않으므로 "0" 으로 정의합니다. (옛날 사람...)


위의 내용을 적용하고 실행하면 다음과 같이 됩니다.



한국 상황에 맞게, 요일까지 정확히 표시할 수 있는 것을 확인했습니다.



FIN

ESP32 의 WiFi 구현이 얼마나 간단한지를 확인해 보기 위해 NTP 서비스를 활용해 봤습니다.
앞으로는 ESP32 를 통하여 다양한 project 를 해봐야 겠네요.

끝.


And

Hardware | ESP32 Deep sleep 알아보기

|

ESP32 는 WiFi 및 Bluetooth 에 추가하여 Dual-core CPU 에 sensor 등, 작은 사이즈에 많은 기능을 내포하고 있습니다.

본격적인 IoT 생활을 위해 Arduino 보드에서 ESP32 로 넘어가는 중이라 ESP32 에 대해 공부하고 있습니다.


지금까지 작성된 ESP32 에 관한 글들은 아래 포스트들을 참고해 주세요.


* Hardware | ESP32 Cryptographic HW 가속 확인해 보기
    - https://chocoball.tistory.com/entry/Hardware-ESP32-Cryptographic-HW-acceleration

* Hardware | EPS32 PWM 기능 확인해 보기
    - https://chocoball.tistory.com/entry/Hardware-EPS32-PWM

* Hardware | ESP32 의 internal sensor 확인해 보기
    - https://chocoball.tistory.com/entry/Hardware-ESP32-internal-sensors

* Hardware | ESP32 의 Dual core 확인해 보기
    - https://chocoball.tistory.com/entry/Hardware-ESP32-Dual-core

* Hardware | ESP32 스펙 확인해 보기
    - https://chocoball.tistory.com/entry/Hardware-ESP32-spec-check

* Hardware | ESP32 간단 사용기
    - https://chocoball.tistory.com/entry/Hardware-simple-review-ESP32



1. Power Modes


ESP32 는 사용 전력량을 알맞게 활용할 수 있도록 5가지 Power 모드를 제공하고 있습니다. Off-Grid 에서의 활용에서는 필수겠죠.



아래 테이블은, 각 mode 들에 따른 ESP32 부위별 active / inactive 와 사용 전력 정보 입니다.


* Insight Into ESP32 Sleep Modes & Their Power Consumption
    - https://lastminuteengineers.com/esp32-sleep-modes-power-consumption/


--------------------------------------------------------------------------------
| Power Mode  | Active                 | Inactive               | Power        |
|             |                        |                        | Consumption  |
|------------------------------------------------------------------------------|
| Active      | WiFi, Bluetooth, Radio |                        | 160 ~ 260 mA |
|             | ESP32 Core             |                        |              |
|             | ULP Co-processor       |                        |              |
|             | Peripherals, RTC       |                        |              |
|------------------------------------------------------------------------------|
| Modem Sleep | ESP32 Core             | WiFi, Bluetooth, Radio |   3 ~ 20 mA  |
|             | ULP Co-processor, RTC  | Peripherals            |              |
|------------------------------------------------------------------------------|
| Light Sleep | ULP Co-processor, RTC  | WiFi, Bluetooth, Radio |     0.8 mA   |
|             | ESP32 Core (Paused)    | Peripherals            |              |
|------------------------------------------------------------------------------|
| Deep Sleep  | ULP Co-processor, RTC  | WiFi, Bluetooth, Radio |     10 uA    |
|             |                        | ESP32 Core, Peripherals|              |
|------------------------------------------------------------------------------|
| Hibernation | RTC                    | ESP32 Core             |     2.5 uA   |
|             |                        | ULP Co-processor       |              |
|             |                        | WiFi, Bluetooth, Radio |              |
|             |                        | Peripherals            |              |
--------------------------------------------------------------------------------


사용하지 않는 부분을 죽이고 최대한 사용 전력을 아끼는 방법입니다.

사양서에는, 좀더 자세한 power mode 별 소비 전력이 안내되어 있습니다.



이번 포스트에서 집중적으로 확인해 볼 Deep sleep 에서는 CPU 를 사용하지 않고, 소전력으로 돌아가는 ULP processor 를 활용합니다.



참고고, ESP32 에서 사용되는 전력의 많은 부분은 역시 WiFi/Bluetooth 이군요.





2. RTC_IO / Touch


Deep sleep 시에 ESP32 를 깨우거나 입력을 받아들이는 pin 은 RTC_IO / Touch 핀들 입니다.

즉, 이 pin 들을 통하여 ULP co-processor 에 자극을 줘서 deep sleep 에서 깨어날 수 있도록 open 된 핀들이라고 할 수 있겠네요.

참고로 모든 Touch 핀들은 RTC_IO 핀들에 포함되어 있습니다.





3. 깨우기 - timer


마침 Examples 에 정갈하게 소스가 올라와 있으니, 이걸 이용해서 확인해 봅니다.

File > Examples > ESP32 > DeepSleep > TimerWakeup


원본 소스는 다음과 같습니다. 5초마다 깼다가 바로 잠드는 시퀀스로 짜여져 있습니다.

wakeup_reason 을 통해, timer 외에 touch 나 external pin 에 의한 확인도 가능하게 만들어져 있네요.


/*
Simple Deep Sleep with Timer Wake Up
=====================================
ESP32 offers a deep sleep mode for effective power
saving as power is an important factor for IoT
applications. In this mode CPUs, most of the RAM,
and all the digital peripherals which are clocked
from APB_CLK are powered off. The only parts of
the chip which can still be powered on are:
RTC controller, RTC peripherals ,and RTC memories

This code displays the most basic deep sleep with
a timer to wake it up and how to store data in
RTC memory to use it over reboots

This code is under Public Domain License.

Author:
Pranav Cherukupalli - cherukupallip@gmail.com
*/

#define uS_TO_S_FACTOR 1000000ULL  /* Conversion factor for micro seconds to seconds */
#define TIME_TO_SLEEP  5        /* Time ESP32 will go to sleep (in seconds) */

RTC_DATA_ATTR int bootCount = 0;

/*
Method to print the reason by which ESP32
has been awaken from sleep
*/
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); //Take some time to open up the Serial Monitor

  //Increment boot number and print it every reboot
  ++bootCount;
  Serial.println("Boot number: " + String(bootCount));

  //Print the wakeup reason for ESP32
  print_wakeup_reason();

  /*
  First we configure the wake up source
  We set our ESP32 to wake up every 5 seconds
  */
  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");

  /*
  Next we decide what all peripherals to shut down/keep on
  By default, ESP32 will automatically power down the peripherals
  not needed by the wakeup source, but if you want to be a poweruser
  this is for you. Read in detail at the API docs
  http://esp-idf.readthedocs.io/en/latest/api-reference/system/deep_sleep.html
  Left the line commented as an example of how to configure peripherals.
  The line below turns off all RTC peripherals in deep sleep.
  */
  //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");

  /*
  Now that we have setup a wake cause and if needed setup the
  peripherals state in deep sleep, we can now start going to
  deep sleep.
  In the case that no wake up sources were provided but deep
  sleep was started, it will sleep forever unless hardware
  reset occurs.
  */
  Serial.println("Going to sleep now");
  Serial.flush(); 
  esp_deep_sleep_start();
  Serial.println("This will never be printed");
}

void loop(){
  //This is not going to be called
}


Serial Monitor 를 통해, 5초마다 깨어나는 상황을 확인 할 수 있습니다.





4. 깨우기 - touch pin


터치센서를 통하여 잠에서 깨우는 소스 입니다. 이것도 마찬가지로 기본 제공되는 Example 을 이용하여 확인해 봤습니다.


File > Examples > ESP32 > DeepSleep > TouchWakeup

/*
Deep Sleep with Touch Wake Up
=====================================
This code displays how to use deep sleep with
a touch as a wake up source and how to store data in
RTC memory to use it over reboots

This code is under Public Domain License.

Author:
Pranav Cherukupalli - cherukupallip@gmail.com
*/

#define Threshold 40 /* Greater the value, more the sensitivity */

RTC_DATA_ATTR int bootCount = 0;
touch_pad_t touchPin;
/*
Method to print the reason by which ESP32
has been awaken from sleep
*/
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;
  }
}

/*
Method to print the touchpad by which ESP32
has been awaken from sleep
*/
void print_wakeup_touchpad(){
  touchPin = esp_sleep_get_touchpad_wakeup_status();

  switch(touchPin)
  {
    case 0  : Serial.println("Touch detected on GPIO 4"); break;
    case 1  : Serial.println("Touch detected on GPIO 0"); break;
    case 2  : Serial.println("Touch detected on GPIO 2"); break;
    case 3  : Serial.println("Touch detected on GPIO 15"); break;
    case 4  : Serial.println("Touch detected on GPIO 13"); break;
    case 5  : Serial.println("Touch detected on GPIO 12"); break;
    case 6  : Serial.println("Touch detected on GPIO 14"); break;
    case 7  : Serial.println("Touch detected on GPIO 27"); break;
    case 8  : Serial.println("Touch detected on GPIO 33"); break;
    case 9  : Serial.println("Touch detected on GPIO 32"); break;
    default : Serial.println("Wakeup not by touchpad"); break;
  }
}

void callback(){
  //placeholder callback function
}

void setup(){
  Serial.begin(115200);
  delay(1000); //Take some time to open up the Serial Monitor

  //Increment boot number and print it every reboot
  ++bootCount;
  Serial.println("Boot number: " + String(bootCount));

  //Print the wakeup reason for ESP32 and touchpad too
  print_wakeup_reason();
  print_wakeup_touchpad();

  //Setup interrupt on Touch Pad 3 (GPIO15)
  touchAttachInterrupt(T3, callback, Threshold);

  //Configure Touchpad as wakeup source
  esp_sleep_enable_touchpad_wakeup();

  //Go to sleep now
  Serial.println("Going to sleep now");
  esp_deep_sleep_start();
  Serial.println("This will never be printed");
}

void loop(){
  //This will never be reached
}


GPIO15 번을 손으로 터치하면 깨어납니다.



Serial Monitor 에서도 touch pin 에서의 감지를 알려 줍니다.





5. 깨우기 - EXT(0) external wake ups


Pin 의 HIGH/LOW 입력을 통하여 깨우는 방법 입니다.


File > Examples > ESP32 > DeepSleep > ExternalWakeup


/*
Deep Sleep with External Wake Up
=====================================
This code displays how to use deep sleep with
an external trigger as a wake up source and how
to store data in RTC memory to use it over reboots

This code is under Public Domain License.

Hardware Connections
======================
Push Button to GPIO 33 pulled down with a 10K Ohm
resistor

NOTE:
======
Only RTC IO can be used as a source for external wake
source. They are pins: 0,2,4,12-15,25-27,32-39.

Author:
Pranav Cherukupalli -cherukupallip@gmail.com
*/

//#define BUTTON_PIN_BITMASK 0x200000000 // 2^33 in hex
#define BUTTON_PIN_BITMASK 0x16 // 2^4 in hex

RTC_DATA_ATTR int bootCount = 0;

/*
Method to print the reason by which ESP32
has been awaken from sleep
*/
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); //Take some time to open up the Serial Monitor

  //Increment boot number and print it every reboot
  ++bootCount;
  Serial.println("Boot number: " + String(bootCount));

  //Print the wakeup reason for ESP32
  print_wakeup_reason();

  /*
  First we configure the wake up source
  We set our ESP32 to wake up for an external trigger.
  There are two types for ESP32, ext0 and ext1 .
  ext0 uses RTC_IO to wakeup thus requires RTC peripherals
  to be on while ext1 uses RTC Controller so doesnt need
  peripherals to be powered on.
  Note that using internal pullups/pulldowns also requires
  RTC peripherals to be turned on.
  */
//  esp_sleep_enable_ext0_wakeup(GPIO_NUM_33,1); //1 = High, 0 = Low
  esp_sleep_enable_ext0_wakeup(GPIO_NUM_4,1); //1 = High, 0 = Low

  //If you were to use ext1, you would use it like
  //esp_sleep_enable_ext1_wakeup(BUTTON_PIN_BITMASK,ESP_EXT1_WAKEUP_ANY_HIGH);

  //Go to sleep now
  Serial.println("Going to sleep now");
  esp_deep_sleep_start();
  Serial.println("This will never be printed");
}

void loop(){
  //This is not going to be called
}


원본 소스는 GPIO_33 번을 활용하게 되어 있으나, 핀 배열상 GPIO_4 로 바꾸도록 수정 해 봤습니다.

Linux 의 파일 시스템에서, 쓰기/읽기 정의에 사용되는 bit mask 방법을 사용하는 군요.


2^(pin 번호) 를 16진수로 표현하여 정의합니다. GPIO_4 이므로, 우선 2 의 4승 계산은 다음과 같습니다.


2^4 = 16



위의 결과를 16진수로 변경해야 합니다. 아래 사이트의 converter 를 이용하면 편합니다.


* Decimal to Hexadecimal converter
    - https://www.rapidtables.com/convert/number/decimal-to-hex.html



최종적으로 2^4 = 16 > 10 (Hexadecimal) 가 됩니다.


...

//#define BUTTON_PIN_BITMASK 0x200000000 // 2^33 in hex
#define BUTTON_PIN_BITMASK 0x10 // 2^4 in hex

...

//  esp_sleep_enable_ext0_wakeup(GPIO_NUM_33,1); //1 = High, 0 = Low
  esp_sleep_enable_ext0_wakeup(GPIO_NUM_4,1); //1 = High, 0 = Low

...


BITMASK 값과 ext0GPIO_NUM_4 로 바꾸어 주면 정의가 완료 됩니다.
회로를 아래처럼 꾸며, 스위치를 누르면 깨어나는 방법입니다.


실제 사진은 다음과 같습니다.



정상 작동 되는군요.





6. 깨우기 - EXT(1) external wake ups


외부 입력을 통한 방법은 위의 EXT(0) 와 같으나, 이번에는 두 개의 스위치를 이용하는 방법 입니다.


/*
Deep Sleep with External Wake Up
=====================================
This code displays how to use deep sleep with
an external trigger as a wake up source and how
to store data in RTC memory to use it over reboots
 
This code is under Public Domain License.
 
Hardware Connections
======================
Push Button to GPIO 33 pulled down with a 10K Ohm
resistor
 
NOTE:
======
Only RTC IO can be used as a source for external wake
source. They are pins: 0,2,4,12-15,25-27,32-39.
 
Author:
Pranav Cherukupalli - cherukupallip@gmail.com
*/
 
#define BUTTON_PIN_BITMASK 0x8004 // GPIOs 2 and 15
 
RTC_DATA_ATTR int bootCount = 0;
 
/*
Method to print the reason by which ESP32
has been awaken from sleep
*/
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;
  }
}
 
/*
Method to print the GPIO that triggered the wakeup
*/
void print_GPIO_wake_up(){
  int GPIO_reason = esp_sleep_get_ext1_wakeup_status();
  Serial.print("GPIO that triggered the wake up: GPIO ");
  Serial.println((log(GPIO_reason))/log(2), 0);
}
   
void setup(){
  Serial.begin(115200);
  delay(1000); //Take some time to open up the Serial Monitor
 
  //Increment boot number and print it every reboot
  ++bootCount;
  Serial.println("Boot number: " + String(bootCount));
 
  //Print the wakeup reason for ESP32
  print_wakeup_reason();
 
  //Print the GPIO used to wake up
  print_GPIO_wake_up();
 
  /*
  First we configure the wake up source
  We set our ESP32 to wake up for an external trigger.
  There are two types for ESP32, ext0 and ext1 .
  ext0 uses RTC_IO to wakeup thus requires RTC peripherals
  to be on while ext1 uses RTC Controller so doesnt need
  peripherals to be powered on.
  Note that using internal pullups/pulldowns also requires
  RTC peripherals to be turned on.
  */
  //esp_deep_sleep_enable_ext0_wakeup(GPIO_NUM_15,1); //1 = High, 0 = Low
 
  //If you were to use ext1, you would use it like
  esp_sleep_enable_ext1_wakeup(BUTTON_PIN_BITMASK,ESP_EXT1_WAKEUP_ANY_HIGH);
 
  //Go to sleep now
  Serial.println("Going to sleep now");
  delay(1000);
  esp_deep_sleep_start();
  Serial.println("This will never be printed");
}
 
void loop(){
  //This is not going to be called
}


여기서의 포인트는, 입력을 받는 복수의 GPIO 번호를 더해서 BITMASK 를 구하는 것 입니다.

사용된 GPIO 정보는 2번과 15번 입니다.


GPIO_2 + GPIO_15 > 2^2 + 2^15 = 32772



32772 의 16진수는 8004 입니다.



원본 소스에서 아래처럼 GPIO 의 BITMASK 변경과, 어떤 GPIO 가 눌렀는지의 표시, 그리고 EXT1 을 정의해 줍니다.


...

#define BUTTON_PIN_BITMASK 0x8004 // GPIOs 2 and 15
...

/*
Method to print the GPIO that triggered the wakeup
*/
void print_GPIO_wake_up(){
  int GPIO_reason = esp_sleep_get_ext1_wakeup_status();
  Serial.print("GPIO that triggered the wake up: GPIO ");
  Serial.println((log(GPIO_reason))/log(2), 0);
}
  
...

  //If you were to use ext1, you would use it like
  esp_sleep_enable_ext1_wakeup(BUTTON_PIN_BITMASK,ESP_EXT1_WAKEUP_ANY_HIGH);

...


회로는 다음과 같이 스위치를 연결 했습니다. EXT0 와 다른 것은 복수 (두 개) 의 스위치를 입력받게 하는 것 입니다.



Serial Monitor 의 결과는 다음과 같아요. 어느 GPIO 핀에서 입력 받았는지를 표시해 줍니다.





7. 전류 확인 - Deep sleep


실재로 전류 변화가 있는지 확인해 봤습니다.



음... 그리 많이 차이나지 않군요.

Examples 에서 제공되는 기본 소스는 Wake up 만 확인하는 소스이지, 계산을 시키거나 하는 것이 아니라서 그런 것 같습니다.





FIN


배터리를 가지고 동작하는 장비들은 필수로 가지고 있어야 할 Power mode 들, 특히 Deep sleep 에 대해 알아 봤습니다.

전력 소비가 가장 심한 WiFi/Bluetooth 부분을 어떻게 활용하면서 운용해야 하는지를 많이 고민해야 할 것 같네요.


- WiFi/Bluetooth 연결 정보는 연결 실패 exception 이나 스케줄에 따라 실시

- 가능한 정보는 memory 에 저장하여 꺼내 쓰는 방식으로

- 배터리 방전 threshold 값을 모니터링 하고, 일정 값 이하로 내려가면 지속적인 alert 발생

- WiFi/Bluetooth 에 사용되는 전류량을 컨트롤 하여, 근거리 통신 -> 중거리 -> 장거리 통신으로 연결하게끔 구성

- DTIM (Delivery Traffic Indication Message) beacon mechanism 등을 활용

- 등등...



And

Hardware | ESP32 Cryptographic HW 가속 확인해 보기

|

ESP32 에 관한 글들은 아래 링크들을 참고해 주세요.


* Hardware | EPS32 PWM 기능 확인해 보기
    - https://chocoball.tistory.com/entry/Hardware-EPS32-PWM

* Hardware | ESP32 의 internal sensor 확인해 보기
    - https://chocoball.tistory.com/entry/Hardware-ESP32-internal-sensors

* Hardware | ESP32 의 Dual core 확인해 보기
    - https://chocoball.tistory.com/entry/Hardware-ESP32-Dual-core

* Hardware | ESP32 스펙 확인해 보기
    - https://chocoball.tistory.com/entry/Hardware-ESP32-spec-check

* Hardware | ESP32 간단 사용기
    - https://chocoball.tistory.com/entry/Hardware-simple-review-ESP32



1. Cryptographic Hardware Acceleration


한 13여년 전에 웹 서비스 구축 시, HTTPS (SSL) 처리에 CPU 연산을 너무 많이 사용해서 골치가 아팠던 경험이 있습니다.

당시에는 NIC 에 붙어있는 Intel 칩에서 SSL 가속 처리를 못해줘, OS 에서 처리하다 보니 CPU 들이 죽어 나갔죠.


막 HW 가속기 (PCI daughter card 형식) 들이 등장하기도 했습니다만, 어디까지나 실험적인 제품들이었고, OS 와 HW 특성을 많이 타다 보니 PoC 단계에서도 그닥 실효를 거두지 못했었습니다.


암호 연산에 대해서는 요즘 NIC 나 CPU 자체적으로 전용 명령어 set을 가지고 지원하는 시대이다 보니, 예전같은 걱정은 말끔히 사라졌네요.


근래에 출시된 ESP32 에도, 이 암호 연산용 HW 가속 기능이 내장되어 있습니다!

다이어그램 상, SHA / RSA / AES / RNG 등이 있네요.



사양서에도 이 HW Accelerator 에 대한 안내가 되어 있습니다.



Cryptographic hardware acceleration

- AES, SHA-2, RSA, elliptic curve cryptography (ECC), random number generator (RNG)


이번 글은 위의 HW Accelerator 의 몇 가지 기능 중, ESP32 의 hardware AES 에 대해 알아보고자 합니다.




2. AES


미국 정부가 1990년 후반까지 사용하고 있던 DES 암호화 기법이, 약 30대 정도의 PC 를 가지고 뚫리면서, 새로운 암호화 기법을 찾게 됩니다. 공모 결과 AES 가 채택되면서 유명해진 암호화 기법이에요.


AES 는 "Advanced Encryption Standard" 의 약자로 cryptographic symmetric cipher algorithm 을 기반으로 encryption 과 decryption 양쪽에 사용될 수 있는 장점을 가지고 있습니다.

참고로 아래 두 가지의 parameter 를 필요로 합니다.


IV (Initial Vector)

맨 처음 block 을 XOR 처리를 할 때, 덮어 씌우는 data block 이 존재하지 않습니다. 이를 보충해 주기 위한 인위적인 블럭이 IV 입니다.


Encryption Key

암호화 / 복호화에 사용되는 고유의 키 입니다.



너무 자세한 설명에 들어가면, 저의 지식이 바닦 치는 것이 보이기에 여기서 그만 합니다.

인터넷에 관련된 문서 및 동영상들이 어마어마 하니, 자세히 공부해 보고 싶으신 분을 넓은 인터넷의 세계로...




3. Software AES - ESP32


HW 가속을 시험해 보기에 앞서, AES 를 소프트웨어적으루 구현해본 분이 계셔서 따라 해봤습니다.


* AES Encryption/Decryption using Arduino Uno
    - https://www.arduinolab.net/aes-encryptiondecryption-using-arduino-uno/


우선 필요한 것은, Spaniakos 라는 분이 만드신 AES 라이브러리를 설치해 줍니다. 아래 Github 에서 라이브러리를 다운 받습니다.


* AES for microcontrollers (Arduino & Raspberry pi)
    - https://github.com/spaniakos/AES



그리고, Arduino libraries 폴더에 심어 놓으면 됩니다.



기본 준비가 되었으니, ESP32 에서 AES-CBC 방식의 암호화/복호화를 실행 해봅니다.


/*------------------------------------------------------------------------------ 
Program:      aesEncDec 
 
Description:  Basic setup to test AES CBC encryption/decryption using different 
              key lengths.
 
Hardware:     Arduino Uno R3 
 
Software:     Developed using Arduino 1.8.2 IDE
 
Libraries:    
              - AES Encryption Library for Arduino and Raspberry Pi: 
                https://spaniakos.github.io/AES/index.html
 
References: 
              - Advanced Encryption Standard by Example: 
              http://www.adamberent.com/wp-content/uploads/2019/02/AESbyExample.pdf
              - AES Class Reference: https://spaniakos.github.io/AES/classAES.html
 
Date:         July 9, 2017
 
Author:       G. Gainaru, https://www.arduinolab.net
              (based on AES library documentation and examples)
------------------------------------------------------------------------------*/
#include "AES.h"

AES aes ;

unsigned int keyLength [3] = {128, 192, 256}; // key length: 128b, 192b or 256b

byte *key = (unsigned char*)"01234567890123456789012345678901"; // encryption key
byte plain[] = "https://chocoball.tistory.com/entry/Hardware-ESP32-Cryptographic-hardware-acceleration"; // plaintext to encrypt

unsigned long long int myIv = 36753562; // CBC initialization vector; real iv = iv x2 ex: 01234567 = 0123456701234567

void setup () {
	Serial.begin(115200);
}

void loop () {
	for (int i=0; i < 3; i++) {
		Serial.print("- key length [b]: ");
		Serial.println(keyLength [i]);
		aesTest (keyLength[i]);
		delay(2000);
	}
}

void aesTest (int bits) {
	aes.iv_inc();
	
	byte iv [N_BLOCK];
	int plainPaddedLength = sizeof(plain) + (N_BLOCK - ((sizeof(plain)-1) % 16)); // length of padded plaintext [B]
	byte cipher [plainPaddedLength]; // ciphertext (encrypted plaintext)
	byte check [plainPaddedLength]; // decrypted plaintext
	
	aes.set_IV(myIv);
	aes.get_IV(iv);
	
	Serial.print("- encryption time [us]: ");
	unsigned long ms = micros ();
	aes.do_aes_encrypt(plain, sizeof(plain), cipher, key, bits, iv);
	Serial.println(micros() - ms);
	
	aes.set_IV(myIv);
	aes.get_IV(iv);
	
	Serial.print("- decryption time [us]: ");
	ms = micros ();
	aes.do_aes_decrypt(cipher,aes.get_size(),check,key,bits,iv); 
	Serial.println(micros() - ms);
	
	Serial.print("- plain:   ");
	aes.printArray(plain,(bool)true); //print plain with no padding
	
	Serial.print("- cipher:  ");
	aes.printArray(cipher,(bool)false); //print cipher with padding
	
	Serial.print("- check:   ");
	aes.printArray(check,(bool)true); //print decrypted plain with no padding
	
	Serial.print("- iv:      ");
	aes.printArray(iv,16); //print iv
	printf("\n-----------------------------------------------------------------------------------\n");
}


암호화를 걸 평문은, 이 포스트의 URL 을 사용했습니다. :-)



암호화/복호화 잘 됩니다. 속도도 좋네요.




4. Software AES - ATmega328


비교 대상으로 궁금하여, ATmega328 을 탑재한 Arduino nano 로 동일한 계산을 시켜보기로 합니다.

다만, "AES.h" 라이브러리를 include 한다고 제대로 실행되진 않는군요.


	aes.printArray(plain,(bool)true); //print plain with no padding


이유는, ATmega328 의 라이브러리에는 위의 printArray 에서 사용하는 printf_P 함수가 없기 때문입니다. (AES.cpp 에서 정의됨)

ESP32 의 FreeRTOS 에는 C 라이브러리 기본 탑재로 문제 없이 동작하지만, Arduino nano 에서는 동작하지 않습니다.


그리하여, 이를 대신할 function 을 만들어 봤는데, 징그럽게도 동작하지 않더군요.

수많은 삽질을 통해, 배열을 다른 함수의 인자로 전달하려면 배열의 pointer 와 그 배열의 크기를 명시해야 하는 것을 알게 되었습니다.

결국 아래처럼 변경하여 Arduino nano 에서도 동작을 성공 시켰습니다.


...

	showArray(iv, array_size_iv, 1);

...

void showArray (byte *result, int array_length, int hex_conv) {
	for (int i=0; i < array_length; i++) {
		if (hex_conv) {
			Serial.print(result[i], HEX);
		} else {
			Serial.print((char)result[i]);
		}
	}
	Serial.println();
}


최종 소스는 다음과 같습니다.


#include "AES.h"

AES aes ;

unsigned int keyLength [3] = {128, 192, 256}; // key length: 128b, 192b or 256b

byte *key = (unsigned char*)"01234567890123456789012345678901"; // encryption key
byte plain[] = "https://chocoball.tistory.com/entry/Hardware-ESP32-Cryptographic-hardware-acceleration"; // plaintext to encrypt

unsigned long long int myIv = 36753562; // CBC initialization vector; real iv = iv x2 ex: 01234567 = 0123456701234567

void setup () {
	Serial.begin(115200);
}

void loop () {
	for (int i=0; i < 3; i++) {
		Serial.print("- key length [b]: ");
		Serial.println(keyLength [i]);
		aesTest (keyLength[i]);
		delay(2000);
	}
}

void aesTest (int bits) {
	aes.iv_inc();
	
	byte iv [N_BLOCK];
	int plainPaddedLength = sizeof(plain) + (N_BLOCK - ((sizeof(plain)-1) % 16)); // length of padded plaintext [B]
	byte cipher [plainPaddedLength]; // ciphertext (encrypted plaintext)
	byte check [plainPaddedLength]; // decrypted plaintext
	
	aes.set_IV(myIv);
	aes.get_IV(iv);
	
	Serial.print("- encryption time [us]: ");
	unsigned long ms = micros ();
	aes.do_aes_encrypt(plain, sizeof(plain), cipher, key, bits, iv);
	Serial.println(micros() - ms);
	
	aes.set_IV(myIv);
	aes.get_IV(iv);
	
	Serial.print("- decryption time [us]: ");
	ms = micros ();
	aes.do_aes_decrypt(cipher,aes.get_size(),check,key,bits,iv);
	Serial.println(micros() - ms);
	
	Serial.print("- plain:   ");
	//aes.printArray(plain,(bool)true); //print plain with no padding
	int array_size_p = sizeof(plain);
	showArray(plain, array_size_p, 0);
	
	Serial.print("- cipher:  ");
	//aes.printArray(cipher,(bool)false); //print cipher with padding
	int array_size_ci = sizeof(cipher);
	showArray(cipher, array_size_ci, 0);
	
	Serial.print("- check:   ");
	//aes.printArray(check,(bool)true); //print decrypted plain with no padding
	int array_size_ch = sizeof(check);
	showArray(check, array_size_ch, 0);
	
	Serial.print("- iv:      ");
	//aes.printArray(iv,16); //print iv
	int array_size_iv = sizeof(iv);
	showArray(iv, array_size_iv, 1);
	Serial.println("-----------------------------------------------------------------------------------");
}

void showArray (byte *result, int array_length, int hex_conv) {
	for (int i=0; i < array_length; i++) {
		if (hex_conv) {
			Serial.print(result[i], HEX);
		} else {
			Serial.print((char)result[i]);
		}
	}
	Serial.println();
}


아래는 Arduino nano 에서 실행시킨 결과 입니다.

ESP32 에서 Software 로 돌린 AES 결과와 비교시, 걸린 시간 빼곤 완벽히 동일합니다.



ESP32 vs. ATmega328 의 CPU 차에 의한 software AES 계산은 encryption = 27 배, decryption = 20 배 정도 차이 났습니다.


----------------------------------------------
| bits | ESP32 | ATmega328 | diff. (multiply)|
|--------------------------------------------|
| 128  |  159  |   4396    |       27.6      |
|      |  267  |   5388    |       20.1      |
|--------------------------------------------|
| 192  |  189  |   5156    |       27.2      | 
|      |  321  |   6392    |       19.9      |
|--------------------------------------------|
| 256  |  220  |   5964    |       27.1      |
|      |  376  |   7432    |       19.7      |
----------------------------------------------


ESP32 를 찬양하라!





5. Hardware AES - library


마지막으로 ESP32 의 HW AES 를 걸어볼 차례 입니다.

HW accelerator 의 Native library 는 아래 글에서 설명이 잘 되어 있습니다.


* AES-CBC encryption or decryption operation
    - https://tls.mbed.org/api/aes_8h.html#a321834eafbf0dacb36dac343bfd6b35d


요는 mbedtls 함수를 이용하면, HW accelerator 를 사용할 수 있게 되는군요. 키 포인트는 "mbedtls_aes_crypt_cbc" 함수가 되겠습니다.

int mbedtls_aes_crypt_cbc ( mbedtls_aes_context *	ctx,
							int						mode,
							size_t					length,
							unsigned char			iv[16],
							const unsigned char *	input,
							unsigned char *			output
)


각 변수들의 정의 입니다.


---------------------------------------------------------------------------------------------------
| Parameters | Meaning                                                                            |
---------------------------------------------------------------------------------------------------
|    ctx     | The AES context to use for encryption or decryption.                               |
|            | It must be initialized and bound to a key.                                         |
---------------------------------------------------------------------------------------------------
|    mode    | The AES operation: MBEDTLS_AES_ENCRYPT or MBEDTLS_AES_DECRYPT.                     |
---------------------------------------------------------------------------------------------------
|   length   | The length of the input data in Bytes.                                             |
|            | This must be a multiple of the block size (16 Bytes).                              |
---------------------------------------------------------------------------------------------------
|    iv      | Initialization vector (updated after use).                                         |
|            | It must be a readable and writeable buffer of 16 Bytes.                            |
---------------------------------------------------------------------------------------------------
|   input    | The buffer holding the input data. It must be readable and of size length Bytes.   |
---------------------------------------------------------------------------------------------------
|   output   | The buffer holding the output data. It must be writeable and of size length Bytes. |
---------------------------------------------------------------------------------------------------


아래는 실재 구현에 도움이 될 만한 사이트들 입니다. 예제들이 설명되어 있어요.


* ESP32 Arduino: Encryption using AES-128 in ECB mode
    - https://techtutorialsx.com/2018/04/18/esp32-arduino-encryption-using-aes-128-in-ecb-mode/

* ESP32 Arduino Tutorial: Encryption AES128 in ECB mode
    - https://everythingesp.com/esp32-arduino-tutorial-encryption-aes128-in-ecb-mode/

* How to encrypt data with AES-CBC mode
    - https://tls.mbed.org/kb/how-to/encrypt-with-aes-cbc

재미 있는 것은, "mbedtls/aes.h" 의 library 도 동작하지만,

#include "mbedtls/aes.h"


"hwcrypto/aes.h" 라이브러리도 동일한 parameter 와 동작을 보여줍니다. 함수명에 mbedtls 가 붙느냐, esp가 붙느냐의 차이 뿐.


#include "hwcrypto/aes.h"


위의 두 가지 library 는 따로 설치하지 않아도 되는걸 보면, native library 이면서 서로가 copy 버전이 아닐까 하네요.




6. Hardware AES - 확인


위의 Software AES 를 Hardware AES 용으로 변환하면 되겠지만, 아직 지식이 짧은 관계로 아래 소스를 가지고 확인해 봤습니다.

* Example of using hardware AES 256 Crypto in CBC mode on the ESP32 using ESP-IDF
* cnlohr/esp32_aes_example.c

    - https://gist.github.com/cnlohr/96128ef4126bcc878b1b5a7586c624ef

#include "string.h"
#include "stdio.h"
#include "hwcrypto/aes.h"

/*
For Encryption time: 1802.40us (9.09 MB/s) at 16kB blocks.
*/

static inline int32_t _getCycleCount(void) {
	int32_t ccount;
	asm volatile("rsr %0,ccount":"=a" (ccount));
	return ccount;
}

char plaintext[16384];
char encrypted[16384];

void encodetest() {
	uint8_t key[32];
	uint8_t iv[16];
	
	//If you have cryptographically random data in the start of your payload, you do not need
	//an IV. If you start a plaintext payload, you will need an IV.
	memset( iv, 0, sizeof( iv ) );
	
	//Right now, I am using a key of all zeroes. This should change. You should fill the key
	//out with actual data.
	memset( key, 0, sizeof( key ) );
	
	memset( plaintext, 0, sizeof( plaintext ) );
	strcpy( plaintext, "https://chocoball.tistory.com/entry/Hardware-ESP32-Cryptographic-hardware-acceleration" );
	
	//Just FYI - you must be encrypting/decrypting data that is in BLOCKSIZE chunks!!!
	
	esp_aes_context ctx;
	esp_aes_init( &ctx );
	esp_aes_setkey( &ctx, key, 256 );
	int32_t start = _getCycleCount();
	esp_aes_crypt_cbc( &ctx, ESP_AES_ENCRYPT, sizeof(plaintext), iv, (uint8_t*)plaintext, (uint8_t*)encrypted );
	int32_t end = _getCycleCount();
	
	float enctime = (end-start)/240.0;
	Serial.printf( "Encryption time: %.2fus (%f MB/s)\n", enctime, (sizeof(plaintext)*1.0)/enctime );
	//See encrypted payload, and wipe out plaintext.
	
	memset( plaintext, 0, sizeof( plaintext ) );
	
	int i;
	for( i = 0; i < 128; i++ ) {
		Serial.printf( "%02x[%c]%c", encrypted[i], (encrypted[i]>31)?encrypted[i]:' ', ((i&0xf)!=0xf)?' ':'\n' );
	}
	Serial.printf( "\n" );
	
	//Must reset IV.
	//XXX TODO: Research further: I found out if you don't reset the IV, the first block will fail
	//but subsequent blocks will pass. Is there some strange cryptoalgebra going on that permits this?
	Serial.printf( "IV: %02x %02x\n", iv[0], iv[1] );
	memset( iv, 0, sizeof( iv ) );
	
	//Use the ESP32 to decrypt the CBC block.
	Serial.print("- decryption time [us]: ");
	unsigned long ms = micros ();
	esp_aes_crypt_cbc( &ctx, ESP_AES_DECRYPT, sizeof(encrypted), iv, (uint8_t*)encrypted, (uint8_t*)plaintext );
	Serial.println(micros() - ms);
	
	//Verify output
	for( i = 0; i < 128; i++ ) {
		Serial.printf( "%02x[%c]%c", plaintext[i], (plaintext[i]>31)?plaintext[i]:' ', ((i&0xf)!=0xf)?' ':'\n' );
	}
	Serial.printf( "\n" );
	
	esp_aes_free( &ctx );
}

void setup() {
	// put your setup code here, to run once:
	Serial.begin(115200);
	encodetest();
}

void loop() {
	// put your main code here, to run repeatedly:
}


결과는 다음과 같습니다.

위의 Software AES 와 비슷하게 결과를 내도록 소스를 만들면 확연히 비교할 수 있겠으나, 공부를 더 해야 함.


다만, 최종적인 처리 속도는 결코 아래 결과에서 변하지 않는다는 것을 여러 삽질을 통해 발견했으니 이걸로 만족.



Hardware AES 를 서포트하는 전용 명령어 set 이 최적화가 되지 않아, 이런 결과가 나온 것인지 모르겠네요.

지금으로써는 전용 accelerator 를 사용하지 않고, Software AES 를 구현하는 것이 더 속도적인 이득이 있는 듯 보입니다.


단, 여러가지 일을 동시에 처리해야 할 경우, 암호화/복호화 처리 부분만 따로 분리하여 HW accelerator 를 이용한다면, CPU 부하를 분산시켜 효율적인 활용은 가능할 것 같네요.




FIN


혹시, 위의 Hardware AES 결과가 잘못된 방법으로 검증된 것이라면 댓글로 알려주세요.


esp32_technical_reference_manual_en.pdf



Clock 사이클을 바탕으로 이론적인 계산을 해보면 68ns 레벨이라고, 아래 블로그에서 봤는데, 실측과는 많이 다르군요.


* Pwn the ESP32 crypto-core
    - https://limitedresults.com/2019/08/pwn-the-esp32-crypto-core/


Doing simple math, the HW AES-128 encryption process is 68.75ns (@160MHz).


그렇다고 합니다.


And

Hardware | EPS32 PWM 기능 확인해 보기

|

ESP32 에 관한 포스트는 아래를 참고해 주세요.


* Hardware | ESP32 의 internal sensor 확인해 보기
    - https://chocoball.tistory.com/entry/Hardware-ESP32-internal-sensors

* Hardware | ESP32 의 Dual core 확인해 보기
    - https://chocoball.tistory.com/entry/Hardware-ESP32-Dual-core

* Hardware | ESP32 스펙 확인해 보기
    - https://chocoball.tistory.com/entry/Hardware-ESP32-spec-check

* Hardware | ESP32 간단 사용기
    - https://chocoball.tistory.com/entry/Hardware-simple-review-ESP32




1. PWM


ESP32 에는 PWM (Pulse Width Modulation) 기능이 들어가 있습니다.

LED 의 dimming (밝기) 조절이나, LCD panel 의 색조절 등에 사용되는 기법입니다.


일전에 8x8 LED matrix 를 다양한 색을 표현하기 위해, PWM 을 구현해 주는 전용 보드를 사용해서 확인해 본 적이 있습니다.


* Hardware | 8x8 LED matrix 와 Colorduino 이용해 보기
    - https://chocoball.tistory.com/entry/Hardware-8x8-LED-matrix-Colorduino


이반적인 Arduino 에는 이 기능이 기본 내장이 아닌지라, PWM 을 구현하려면 대응 보드를 사용해야 하는 번거로움이 존재합니다.

그치만, ESP32 는 기본 내장이에요!



PWM 을 통한 활용은 LED 뿐 만 아니라, step motor 난 piezo speaker 등에서도 활용할 수 있습니다.



기본 동작은 높은 주파수를 통해, on/off 를 해주는 시간 (duty) 를 변경하면서 조절하는 방법입니다.

당연히 duty 가 길면 길수록 밝기가 세다거나, 지속적인 동작을 보여주는 원리 입니다.

LED, Step motor, 그리고 Piezo 스피커를 작동시키는 동작원리와 완벽히 같습니다.




2. 코딩


지금까지 몇 번 봐왔던 원리인지라, 바로 코딩에 들어가 봅니다. 참조한 사이트는 아래 입니다.


* ESP32 PWM Example
    - https://circuits4you.com/2018/12/31/esp32-pwm-example/


PWM 을 구현하기 위한 명령어는 라이브러리에 준비되어 있으니, 그냥 사용해 줍니다.


* ledcSetup(PWM_Channel_Number, Frequency, resolution)

- Pass three arguments as an input to this function, channel number, frequency and the resolution of PWM channel at inside the setup function only.


* ledcAttachPin(GPIO_PIN , CHANNEL)

- Two arguments. One is the GPIO pin on which we want to get the OUTPUT of signal and second argument is the channel which we produce the signal.


* ledcWrite(CHANNEL, DUTY_CYCLE)

- ledcWrite function is used to generate the signal with a duty cycle value.


ledcSetupledcAttachPin 은 setup() 에서, 실제 구동은 loop() 에서 ledcWrite 를 사용합니다. digitalWrite 와 비슷하죠.

최종적으로 ESP32 보드에 실장되어 있는 LED 를 가지고 PWM 을 확인한 코드가 아래 입니다.


// Generates PWM on Internal LED Pin GPIO 2 of ESP32
#define LED 2 //On Board LED

int brightness = 0; // how bright the LED is
int fadeAmount = 5; // how many points to fade the LED by

// setting PWM properties
const int freq = 5000;
const int ledChannel = 0;
const int resolution = 10; // Resolution 8, 10, 12, 15

void setup() {
	Serial.begin(115200);
	pinMode(LED, OUTPUT);
	
	// configure LED PWM functionalitites
	ledcSetup(ledChannel, freq, resolution);
	
	// attach the channel to the GPIO2 to be controlled
	ledcAttachPin(LED, ledChannel);
}

void loop() {
	// PWM Value varries from 0 to 1023
	Serial.println("10 % PWM");
	ledcWrite(ledChannel, 102);
	delay(2000);
	
	Serial.println("20 % PWM");
	ledcWrite(ledChannel,205);
	delay(2000);
	
	Serial.println("40 % PWM");
	ledcWrite(ledChannel,410);
	delay(2000);
	
	Serial.println("70 % PWM");
	ledcWrite(ledChannel,714);
	delay(2000);
	
	Serial.println("100 % PWM");
	ledcWrite(ledChannel,1024);
	delay(2000);
	
	// Continuous Fading
	Serial.println("Fadding Started");
	while(1) {
		// set the brightness of pin 2:
		ledcWrite(ledChannel, brightness);
		
		// change the brightness for next time through the loop:
		brightness = brightness + fadeAmount;
		
		// reverse the direction of the fading at the ends of the fade:
		if (brightness <= 0 || brightness >= 1023) {
			fadeAmount = -fadeAmount;
		}
		
		// wait for 30 milliseconds to see the dimming effect
		delay(10);
	}
}




3. LED_BUILTIN


위의 코드를 실행하면 Serial Monitor 에서는 다음과 같이 표시됩니다.


소스에서도 알 수 있듯이, 10% > 20% > 40% > 70% > 100% 으로 LED 를 키고, 그 다음부터는 5/1024 씩 증감하면서 dimming 을 표현해 줍니다.

실제 동작 동영상은 다음과 같습니다.




4. 오실로스코프 확인


여기서 끝내면 심심하니, 실제 파형을 확인해 보려 합니다. 참고한 사이트는 다음과 같습니다.


* ESP32 PWM with Arduino IDE (Analog Output)
    - https://randomnerdtutorials.com/esp32-pwm-arduino-ide/


소스 코드는 다음과 같습니다.


// the number of the LED pin
const int ledPin = 16;  // 16 corresponds to GPIO16
const int ledPin2 = 17; // 17 corresponds to GPIO17
const int ledPin3 = 5;  // 5 corresponds to GPIO5

// setting PWM properties
const int freq = 5000;
const int ledChannel = 0;
const int resolution = 8;
 
void setup() {
	// configure LED PWM functionalitites
	ledcSetup(ledChannel, freq, resolution);
	
	// attach the channel to the GPIO to be controlled
	ledcAttachPin(ledPin, ledChannel);
	ledcAttachPin(ledPin2, ledChannel);
	ledcAttachPin(ledPin3, ledChannel);
}

void loop() {
	// increase the LED brightness
	for(int dutyCycle = 0; dutyCycle <= 255; dutyCycle++) {
		// changing the LED brightness with PWM
		ledcWrite(ledChannel, dutyCycle);
		delay(15);
	}
	
	// decrease the LED brightness
	for(int dutyCycle = 255; dutyCycle >= 0; dutyCycle--) {
		// changing the LED brightness with PWM
		ledcWrite(ledChannel, dutyCycle);
		delay(15);
	}
}


3개의 LED 에 PWM 을 거는 소스 입니다.

2개 pin 에는 실제로 LED 를 연결해서 dimming 을 확인하고, 나머지 하나의 pin 에는 오실로스코프를 연결하여 파형을 확인해 봅니다.



이론과 실험이 만나는 동영상 입니다.



당연히 이렇게 될 것이라 알지만, 너무 이쁘게 그래프가 나와서 조금 놀랬습니다. Frequency 와 Duty 값이 정확하게 측정되는 군요.

ESP32 의 PWM 기능은 완벽하군요.




5. Piezo 연결


원리는 같으나, 눈으로 보면 다르게 느껴지는 Piezo 스피커도 확인해 보았습니다. 아래 링크를 참조하였습니다.


* ESP32 Arduino: Controlling a buzzer with PWM
    - https://techtutorialsx.com/2017/07/01/esp32-arduino-controlling-a-buzzer-with-pwm/


PWM 동작하는 GPIO 하나 잡아서 연결하면 됩니다.



저는 piezo 를 D4 = GPIO4 에 연결했습니다.


int freq = 2000;
int channel = 0;
int resolution = 8;
  
void setup() {
	Serial.begin(115200);
	ledcSetup(channel, freq, resolution);
	ledcAttachPin(4, channel);
}
  
void loop() {
	ledcWriteTone(channel, 2000);
	for (int dutyCycle = 0; dutyCycle <= 255; dutyCycle = dutyCycle + 10) {
		Serial.println(dutyCycle);
		ledcWrite(channel, dutyCycle);
		delay(1000);
	}
	
	ledcWrite(channel, 125);
	for (int freq = 255; freq < 10000; freq = freq + 250){
		Serial.println(freq);
		ledcWriteTone(channel, freq);
		delay(1000);
	}
}


처음에는 2000Hz 에서 duty 사이클을 10씩 증가하는 소리이고,

그 다음은 duty 를 125로 고정한 다음, 주파수만 바꿔가면서 소리를 내는 소스 입니다.





FIN


지금까지 ESP32 의 내부 기능들을 확인해 봤습니다.

확인하지 않고 남아있는 기능들이 Deep Sleep 과 Hardware Acceleration (Cryptographic) 정도가 남았네요.


And

Hardware | ESP32 의 internal sensor 확인해 보기

|

지금까지 ESP32 에 대한 글은 아래 링크들에서 확인해 보세요.


* Hardware | ESP32 의 Dual core 확인해 보기
    - https://chocoball.tistory.com/entry/Hardware-ESP32-Dual-core

* Hardware | ESP32 스펙 확인해 보기
    - https://chocoball.tistory.com/entry/Hardware-ESP32-spec-check

* Hardware | ESP32 간단 사용기
    - https://chocoball.tistory.com/entry/Hardware-simple-review-ESP32

이번 글은, ESP32 에 내장된 센서들에 관한 이야기 입니다.




1. 온도 센서


첫 번째로 온도센서에 대해 확인해 봅니다.

내장 센서이다 보니, 회로를 구성할 필요 없이, internal 값만 찾아서 확인해 보면 됩니다.


아래는 소스 입니다.


/* 
 *  ESP32 Internal Temperature Sensor Example
 */
 
 #ifdef __cplusplus
  extern "C" {
 #endif
 
  uint8_t temprature_sens_read();
 
#ifdef __cplusplus
}
#endif
 
uint8_t temprature_sens_read();
//====================================================
//         Setup
//====================================================
void setup() {
  Serial.begin(115200);
}
 
//====================================================
//         Loop
//====================================================
void loop() {
  Serial.print("Temperature: ");
  
  // Convert raw temperature in F to Celsius degrees
  Serial.print((temprature_sens_read() - 32) / 1.8);
  Serial.println(" C");
  delay(1000);
}


내부 함수 "temprature_sens_read()" 를 사용하여 내부 온도 센서 값을 읽어오는 루틴 입니다.



음? 뭔가 이상하군요. 계속 53.33 도씨만을 리턴합니다. 구글링 해봅니다.


* ESP32 internal temperature sensor not working #2422

https://github.com/espressif/arduino-esp32/issues/2422


아... CPU 버전업 되면서, 온도센서가 없어졌네요. -_-;



어쩐지, 예전 CPU diagram 에는 온도센서가 존재하지만,



최신 spec. 문서에는 Temperature sensor 가 없어지고, Embedded Flash 가 대신 들어가 있습니다.



그리하여, Internal temperature sensor 의 값을 불러오면, 정해진 값 - 128 - 만 리턴하게 만들어 진 것을 확인할 수 있었습니다.



2. Hall 센서


자력을 측정하는 센서 입니다. 보통 전류 센서에도 붙어 있죠.



Examples > ESP32 > HallSensor



소스를 보면, "hallRead()" 를 통해서 자력 값을 읽을 수 있습니다.


//Simple sketch to access the internal hall effect detector on the esp32.
//values can be quite low. 
//Brian Degger / @sctv  

int val = 0;
void setup() {
	Serial.begin(115200);
}

void loop() {
	// put your main code here, to run repeatedly:
	val = hallRead();
	// print the results to the serial monitor:
	// Serial.print("sensor = ");
	Serial.println(val); // to graph
	
	delay(50);
}


마침 가지고 있던 네오디뮴 자석으로 확인해 봅니다.



양의 값 (+) 와 음의 값 (-) 이 잘 읽힙니다.

개인적으로는 이 센서가 ESP32 에 필요한 이유는 잘 모르겠습니다. 누가 아시는 분은 댓글로 남겨 주세요.



동영상도 올려 봅니다.





3. 터치 센서


ESP32 에는 터치 센싱을 하는 pin 이 10 개 달려 있습니다.



마찬가지로, 왜 이리 touch sensor 를 많이 가지고 있는지 의문이지만, 스펙상으로는 10개 입니다.

스펙 문서에는 10개로 되어 있지만, Pinheader 로는 9개만 보이네요.



아래처럼 터치를 읽어들이는 소스가 기본 제공됩니다.


Examples > ESP32 > Touch > TouchRead



이미 "touchRead()" 라는 함수가 라이브러리에 준비되어 있군요.


// ESP32 Touch Test
// Just test touch pin - Touch0 is T0 which is on GPIO 4.

void setup() {
	Serial.begin(115200);
	delay(1000); // give me time to bring up serial monitor
	Serial.println("ESP32 Touch Test");
}

void loop() {
	Serial.println(touchRead(T0)); // get value using T0
	delay(1000);
}


결과는 다음과 같이 표시 됩니다. 터치되지 않은 상태는 95 정도이고, 해당 pin 을 손으로 만지면 10 이하로 내려갑니다.



해당 pin 을 터치했을 때, 내장 LED 의 불을 켜주는 소스 입니다. touchRead 의 기준 값은 50 으로 설정되어 있습니다.


// ESP32 Touch Test
// Just test touch pin - Touch0 is T0 which is on GPIO 4.

int LED_BUILTIN = 2;

void setup() {
  // initialize digital pin LED_BUILTIN as an output.
  pinMode(LED_BUILTIN, OUTPUT);
  
  Serial.begin(115200);
  delay(1000); // give me time to bring up serial monitor
  Serial.println("ESP32 Touch Test");
}

void loop() {
  int x = 0;
  Serial.println( x = touchRead(T0) ); // get value using T0
  //delay(1000);
  
  if( x < 50 ) {
    digitalWrite(LED_BUILTIN, HIGH);
    Serial.println("Turn on LED");
    delay(500);
  } else {
    digitalWrite(LED_BUILTIN, LOW);
    Serial.println("Turn off LED");
    delay(500);
  }
}


주의할 것은, LED_BUILTIN 값은 보통 arduino 들은 자동으로 잡아 주지만, IDE 에서 board 선택을 ESP32 Dev Module 로 하면 제대로 동작하지 않습니다. 아마 DOIT ESP32 DEVKIT V1 은 LED_BUILTIN 이 정의되어 있지만, ESP32 Dev Module 은 해당 정의가 없는 듯 합니다.


ESP32 의 내장 LED 는 digital pin 2 이므로, "int LED_BUILTIN = 2" 를 선언해 주면 됩니다.



동영상도 올려 봅니다.





FIN


Arduino 와 비교하여 CPU 도 넘사벽이지만, 내장 센서도 다채롭게 구비되어 있는 ESP32 테스트 해 봤습니다.

다음 글에서는 ESP32 의 PWM 기능에 대해 확인해 보도록 하겠습니다.


And

Hardware | ESP32 의 Dual core 확인해 보기

|

ESP32 대한 지금까지 글은 아래 포스팅들을 참고해 주세요.


* Hardware | ESP32 스펙 확인해 보기
    - https://chocoball.tistory.com/entry/Hardware-ESP32-spec-check

* Hardware | ESP32 간단 사용기
    - https://chocoball.tistory.com/entry/Hardware-simple-review-ESP32




1. Dual core 활용에 앞서


ESP32 의 최장점 중 하나인, dual core 활용에 앞서 개념적인 이야기들이 조금 필요하다고 생각되었다.



그 이유는, 제가 dual core 활용을 이해하고 실행해 보기까지 삽질한 흔적들을 공유하기 위해서 이다.

아직 100% 맞는 이야기 인지는 확신이 들지 않지만, 대략 문제는 없어 보이니, 서두를 조금 길게 하겠다.




2. Arduino IDE 와 ESP-IDF


우선 ESP32 에 프로그램을 올리기 위해서는 coding 하는 환경이 필요한데, 이 개발환경이 ESP-IDF 이다.

보통 ESP-IDF framework 라 부른다.



다만, 우리가 친숙한 Arduino IDE 환경에서도 개발할 수 있도록, Arduino IDE 의 Arduino Core 가 ESP-IDF 를 포함하고 있다.

말하자면, ESP-IDF 의 간편한 interface 인 셈이다.


참고로, Arduino IDE 에서 컴파일한 결과물 보다, ESP-IDF 환경에서 컴파일한 결과물이 대략 65% 정도의 더 빠르다고 하니, ESP32 개발은 가능하면, ESP-IDF 프레임워크에서 개발하는 것이 좋다 하겠다.


살짝 다른 이야기 이지만, 위의 글에서도 설명 되어 있 듯, ESP32 세계에서 이야기 하는 firmware 는, 흔히 OS 기저에 존재하는 HW/OS 사이를 interfacing 해주는 미들웨어가 아니라, 구동 프로그램 자체를 이야기 한다. 헷갈리지 말자.


이 용어의 혼란 때문에, ESP32 의 firmware 를 업데이트 하고자 답도 없는 웹페이지들을 읽어댓다.




3. ESP-IDF FreeRTOS


그럼 자주 등장하는 FreeRTOS 는 도대체 뭔가?


* Quality RTOS & Embedded Software
    - https://www.freertos.org/a00106.html


이름의 약자 부분이 "RTOS - Real Time OS" 인 실시간 처리를 위한 OS이고, 그 중에 가장 유명한 open source 인 RTOS 를 뜻한다.

결국, 아래 발췌한 문구에서 볼 수 있 듯, ESP-IDF framework 는 이 FreeRTOS 실시간 운영 체제를 기반으로 하고 있다.


The ESP-IDF FreeRTOS is a modified version of vanilla FreeRTOS which supports symmetric multiprocessing (SMP).

이 FreeRTOS 덕에, 이 글의 목적인 dual core 를 활용할 수 있게 된 것이다.

처음엔 ESP32Arduino + WiFi 정도로 생각하고 덤볐는데, 완전 deep 하게 들어온 듯 하다.

상하 관계를 정리하면, FreeRTOS + Components > ESP-IDF > Arduino Core > Arduino IDE 되겠다.



AWS 에서도 MQTT 를 위해 FreeRTOS 서비스를 지원하고 있지만, 아래 그림에서 보면 살짤 달라 보인다.

ESP32 에서는 ESP-IDF 하위 layer 에 FreeRTOS 가 위치하지만, AWS FreeRTOS 는 ESP-IDF 상위에 자리하고 있다.





4. SMP


ESP32 에서 dual core 는 CPU 0 - Protocol CPU (PRO_CPU) CPU 1 - Application CPU (APP_CPU)두 가지로 정의되어 사용된다.

보통, PRO_CPU 는 백그라운드 작업이나 WiFi 인터페이싱 쪽을, APP_CPU 는 어플리케이션 쪽에 우선 순위를 둬서 동작하게 된다.

그러다 보니, APP_CPU 는 항상 바쁘고, PRO_CPU 는 많은 시간 놀게 되는, 좋지 않은 효율을 보일 수 있다.


Arduino IDE 에서 코딩하게 되면, setup() / loop() 는 CPU 1 에서 실행되고, 무선관련 동작은 CPU 0 에서 실행된다고 한다.



효율이 좋지 않다고 하더라도, 엄연한 dual core architecture 이며, memory 와 cache 및 외부기기 접근을 공유한다.



Core 이름에서도 알 수 있듯, 통신에 관한 background 처리는 CPU 0 에서 처리하고, 어플리케이션은 CPU 1 에서 하려고 하기 때문에, 효율 좋게 동작할 수 있도록 아래와 같이 CPU core 지정 명령어를 구비해 놓았습니다.


|------------------------------------------------------------------|
| instruction               | meaning                              |
|------------------------------------------------------------------|
| xTaskCreate()             | for single core tasks                |
| xTaskCreatePinnedToCore() | for assigning tasks to specific core |
| xTaskCreateUniversal()    | for making cores used evenly         |
|------------------------------------------------------------------|


Single core 에는 "xTaskCreate()" 를 사용하고, 특정 core 에 할당하고 싶을 때에는 "xTaskCreatePinnedToCore()" 을 사용합니다.

Core 수를 확인하여, core 갯수에 알맞게 task 를 할당하는 것이 "xTaskCreateUniversal()" 입니다.


우리는 core 를 편중되지 않고, 조금 강제적으로 균등하게 사용하기 위해 "xTaskCreatePinnedToCore()" 을 사용할 껍니다.

참고로, 함수의 첫번째 부분에 표시되는 "x..." 는 FreeRTOS 네이티브 명령어를 지정하는 것이라 하네요.




5. Source 기본 구조


기존 Arduino 처럼 코딩하는 것이 아닌, Dual core 만의 규칙이 있습니다. 사실 FreeRTOS 의 규칙이겠죠.

void task1(void *pvParameters) {
	while (1) {
		...
		...
		delay(10);
	}
}

void task2(void *pvParameters) {
	while (1) {
		...
		...
		delay(10);
	}
}


우선 각 core 에 시킬 일들을 미리 정의해 놓습니다. Function 정의와 비슷합니다.

다만, "while(1)" 구문 안에 작업 루틴이 들어가고, 필히 "delay(10)" 가 필요합니다.

Delay 는 10 microseconds 미만이면, 균등하게 core 끼리 일을 나눠 갖지 못합니다. 꼭 10 microseconds 이상으로 설정해야 합니다.


참고로 Arduino IDE 에서 제공하는 "delay(10)" 함수를 사용해도 되나, FreeRTOS 용으로 표현해 보면 다음과 같습니다.
ESP32 를 활용함에 있어, FreeRTOS 용 함수를 사용하는 것이 좀더 빠를 듯 해서입니다.

portTickType delay_10 = 10 / portTICK_RATE_MS;

...
		vTaskDelay(delay_10);
...

setup()loop() 는 다음과 같은 형식 입니다.

void setup() {
	Serial.begin(115200);
	delay(50); // wait for initialization
	
	xTaskCreatePinnedToCore(
		task1,
		"task1",
		8192,
		NULL,
		1,
		NULL,
		PRO_CPU_NUM
	);
	
	xTaskCreatePinnedToCore(
		task2,
		"task2",
		8192,
		NULL,
		0,
		NULL,
		APP_CPU_NUM
	);
}

void loop() {
}


위에서 언급 했던, core 할당 방법 - xTaskCreate() / xTaskCreatePinnedToCore() / xTaskCreateUniversal() - 과, 어느 CPU - PRO_CPU_NUM / APP_CPU_NUM - 를 사용할 것인지를 정의해 줍니다.


위의 예시는, Core 0 / 1 에 강제적으로 task 를 할당한 예 입니다.

자세한 설명은 아래 FreeRTOS 문서를 참고해 보세요.


* FreeRTOS

- https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/system/freertos.html




6. Single Core 활용


Core 한개만을 이용하여, 2승을 계산하는 간단한 코드를 만들어 봤습니다.


portTickType delay_10 = 10 / portTICK_RATE_MS;
int countX = 0;

void task1(void *pvParameters) {
	while (1) {
		for ( int i = 0 ; i < 1000 ; i++ ) {
			pow(2, i);
		}
		countX++;
		vTaskDelay(delay_10);
	}
}
 
void setup() {
	Serial.begin(115200);
	delay(50); // wait for initialization
	
	xTaskCreatePinnedToCore(
		task1,
		"task1",
		8192,
		NULL,
		1,
		NULL,
		PRO_CPU_NUM
	);
}
 
void loop() {
	Serial.println(countX);
	delay(100);
}


2의 1000 승이 완료되면 countX 에 1을 증가하는 방식으로, 일정한 시간 동안 Single 과 Dual 의 계산량 차이를 보기 위한 것입니다.


int countX = 0;

...

		for ( int i = 0 ; i < 1000 ; i++ ) {
			pow(2, i);
		}
		countX++;
...

void loop() {
	Serial.println(countX);
	delay(100);
}


setup() 에서 xTaskCreatePinnedToCore 를 이용하여 task1 하나만 정의하여 돌려 봤습니다.


...

	xTaskCreatePinnedToCore(
		task1,
		"task1",
		8192,
		NULL,
		1,
		NULL,
		PRO_CPU_NUM
	);

...


위에서 CPU core 지정 부분을 PRO_CPU_NUMAPP_CPU_NUM 을 바꿔 해봤지만, 동일한 결과를 보여 줬습니다.



약 50 초 동안, 2의 1000 승을 1600 회 정도 계산했습니다.




7. Dual Core 활용


xTaskCreatePinnedToCorePRO_CPU_NUM / APP_CPU_NUM 를 모두 사용하는 코드 입니다.


portTickType delay_10 = 10 / portTICK_RATE_MS;
int countX = 0;

void task1(void *pvParameters) {
	while (1) {
		for ( int i = 0 ; i < 1000 ; i++ ) {
			pow(2, i);
		}
		countX++;
		vTaskDelay(delay_10);
	}
}

void task2(void *pvParameters) {
	while (1) {
		for ( int i = 0 ; i < 1000 ; i++ ) {
			pow(2, i);
		}
		countX++;
		vTaskDelay(delay_10);
	}
}
 
void setup() {
	Serial.begin(115200);
	delay(50); // wait for initialization
	
	xTaskCreatePinnedToCore(
		task1,
		"task1",
		8192,
		NULL,
		1,
		NULL,
		PRO_CPU_NUM
	);
 
	xTaskCreatePinnedToCore(
		task2,
		"task2",
		8192,
		NULL,
		1,
		NULL,
		APP_CPU_NUM
	);
}
 
void loop() {
	Serial.println(countX);
	delay(100);
}


약 3200 개 정도를 계산해 냈네요. Single core 사용할 때보다, 딱 2배의 숫자 입니다. 이로써, dual core 가 사용되었다는 것을 알 수 있습니다.



Single core 의 계산 처리값과 한 그래프에서 비교하고 싶어서 index 를 추가하고 EXCEL 에서 그래프를 그려 보았습니다.


int x = 0;

...
 
void loop() {
  x++;
  Serial.print(x);
  Serial.print("\t");
  Serial.println(countX);
  delay(100);
}

왼쪽이 index, 오른쪽이 100 마이크로초 동안 2 의 1000 승을 계산한 횟수를 보여줍니다.


생각 외로 처리량이 꽤 좋습니다. Arduino Nano 와는 넘사벽인 성능입니다.


ESP32_dual_core_calc.xlsx



그래프에서 선이 겹쳐 보여 잘 보이지 않지만, PRO_CPU_NUM 이 조금 낮게 나올 것이라고 예상 했지만, WiFi 등을 사용하고 있지 않기 때문에, APP_CPU_NUM 과 동일하게 나왔습니다.


Dual core 를 활용하면서, 정확하게 2배의 계산 처리량을 보여 줬습니다.




FIN


CPU 도 Dual core 에다가 내장 센서, 그리고 Arduino IDE 에서 코딩할 수 있다는 점은 엄청나게 큰 장점일 듯 합니다.

거의 왠만한 프로젝트는 ESP32 하나로 커버 가능할 것 같습니다. EPS32 에 대해 다른 기능들도 차차 알아 보겠습니다.




참고 사이트


- https://www.hackster.io/rayburne/esp32-in-love-with-both-cores-8dd948

- https://www.mgo-tec.com/blog-entry-ledc-pwm-arduino-esp32.html/2

- https://qiita.com/makotaka/items/dd035f4b2db94f87b63c

- https://lang-ship.com/blog/work/esp32-freertos-l03-multitask/

- https://techtutorialsx.com/2017/05/16/esp32-dual-core-execution-speedup/



And

Hardware | ESP32 스펙 확인해 보기

|

1. ESP32 specification


ESP32 는 ATmega328 베이스의 arduino 보다는 훨씬 많은 성능을 가지고 있습니다.



거기에 더하여 ESP32 자체도 버전이 조금씩 달라, 구입 후 실적용 전에 spec. 을 확인해 보는 것이 중요하다고 합니다.




2. 참조 사이트


내부 스펙에 대해 확인할 수 있는 글을 발견하여 소개된 소스를 실행해 봤습니다.


* mgo-tec電子工作
    - https://www.mgo-tec.com/blog-entry-chip-info-esp-wroom-32-esp32.html


* ESP32-WROOM-32
    - https://ht-deko.com/arduino/esp-wroom-32.html


위에서 참조한 사이트의 소스를 그냥 실행하니, 동작은 하지만 compile 시 warning 이 뜨더군요.



이유는, 글쓴이의 ESP-IDF (ESP8266 의 SDK 와 같은 기능) 가 예전 버전을 사용해서 확인했기 때문이었습니다. (2017년 버전)
EFUSE 정보에 접근하는 방법도 바뀌었으며, 특히 Heap Memory 확인 방법이 바뀌었습니다.


...
 //Internal RAM
uint32_t getHeapSize(); //total heap size
uint32_t getFreeHeap(); //available heap
uint32_t getMinFreeHeap(); //lowest level of free heap since boot
uint32_t getMaxAllocHeap(); //largest block of heap that can be allocated at once

the esp.h file: https://github.com/espressif/arduino-esp32/blob/80c110ece70b179ddfe686e8ee45b6c808779454/cores/esp32/Esp.h
...


다행히 업데이트 된 core library 에서 변경된 API 명령어를 찾을 수 있었습니다.



Warning 부분을 모두 확인 했으니, 하나씩 정리해 봅니다.



3. API


ESP32 는, library / API 를 통해 간단하게 컨트롤 할 수 있게 만들어져 있습니다.

자세한 사양을 확인하는 방법도 API 를 통해 확인할 수 있게 되어 있으므로, API 문서만 참고하면 됩니다.


* Miscellaneous System APIs
    - https://docs.espressif.com/projects/esp-idf/en/v3.2.3/api-reference/system/system.html



API 사이트가 잘 만들어져 있습니다.

화면의 왼쪽 밑부분의 버전을 클릭하면, 원하는 version 의 API 문서로 옮겨갈 수 있게 되어 있습니다.



제가 사용하고 있는 ESP-IDF 버전이 v3.2.3-14 이므로, API 문서에서 v3.2.3 을 선택해서 확인 했습니다.




4. API - 사용한 명령어


위에서 설명한 Heap Memory 부분을 제외한 내용 입니다.

ESP32 의 CPU 를 확인할 수 있는 명령어 입니다.



CPU 의 모델과 revision, 그리고 CPU core 갯수 까지 확인 할 수 있습니다.



사용하고 있는 ESP-IDF 버전 확인 명령어 입니다.



위에서 잠깐 언급한 EFUSE 확인용 커멘드 입니다.

확인해 보면, 기기의 기본 MAC 주서는 WiFi Station MAC 주소와 동일하다는 것을 알 수 있습니다. WiFi Station MAC 정보는 세상에서 유일하니, 기기의 유일성을 WiFi Station MAC 로 정의해도 문제는 없겠네요.



WiFi / WiFi Software AP / Bluetooth / Ethernet 의 MAC 주소는 다음과 같은 API 로 정보를 확인 할 수 있습니다.



최종 사용된 API 들 입니다.


	ESP.getEfuseMac()
	ESP.getChipRevision()
	esp_chip_info_t
	esp_chip_info
	ESP.getCpuFreqMHz()
	ESP.getFlashChipSize()
	ESP.getFlashChipSpeed()
	esp_get_idf_version()
	ESP.getHeapSize()
	ESP.getFreeHeap()
	ESP.getMinFreeHeap()
	ESP.getMaxAllocHeap()
	esp_efuse_mac_get_default()
	esp_read_mac(array, ESP_MAC_WIFI_STA)
	esp_read_mac(array, ESP_MAC_WIFI_SOFTAP)
	esp_read_mac(array, ESP_MAC_BT)
	esp_read_mac(array, ESP_MAC_ETH)




5. sketch


참조한 사이트와 ESP-IDF v3.2.3 용으로 조금 바꾼 소스 입니다.


void setup(void) {
	Serial.begin(115200);
	
	uint64_t chipid;
	chipid=ESP.getEfuseMac(); // The chip ID is essentially its MAC address(length: 6 bytes)
	Serial.printf("ESP32 Chip ID = %04X", (uint16_t)(chipid>>32)); // print High 2 bytes
	Serial.printf("%08X\n", (uint32_t)chipid); // print Low 4bytes
	Serial.println("---------------------------------");
	
	Serial.printf("Chip Revision %d\n", ESP.getChipRevision());
	esp_chip_info_t chip_info;
	esp_chip_info(&chip_info);
	Serial.printf("Number of Core: %d\n", chip_info.cores);
	Serial.printf("CPU Frequency: %d MHz\n", ESP.getCpuFreqMHz());  
	Serial.println();
	
	Serial.printf("Flash Chip Size = %d byte\n", ESP.getFlashChipSize());
	Serial.printf("Flash Frequency = %d Hz\n", ESP.getFlashChipSpeed());
	Serial.println();
	
	Serial.printf("ESP-IDF version = %s\n", esp_get_idf_version());
	Serial.println();
	
	Serial.printf("Total Heap Size = %d\n", ESP.getHeapSize());
	Serial.printf("Free Heap Size = %d\n", ESP.getFreeHeap());
	Serial.printf("Lowest Free Heap Size = %d\n", ESP.getMinFreeHeap());
	Serial.printf("Largest Heap Block = %d\n", ESP.getMaxAllocHeap());
	Serial.println();
	
	uint8_t mac0[6];
	esp_efuse_mac_get_default(mac0);
	Serial.printf("Default Mac Address = %02X:%02X:%02X:%02X:%02X:%02X\r\n", mac0[0], mac0[1], mac0[2], mac0[3], mac0[4], mac0[5]);
	
	uint8_t mac3[6];
	esp_read_mac(mac3, ESP_MAC_WIFI_STA);
	Serial.printf("[Wi-Fi Station] Mac Address = %02X:%02X:%02X:%02X:%02X:%02X\r\n", mac3[0], mac3[1], mac3[2], mac3[3], mac3[4], mac3[5]);
	
	uint8_t mac4[7];
	esp_read_mac(mac4, ESP_MAC_WIFI_SOFTAP);
	Serial.printf("[Wi-Fi SoftAP] Mac Address = %02X:%02X:%02X:%02X:%02X:%02X\r\n", mac4[0], mac4[1], mac4[2], mac4[3], mac4[4], mac4[5]);
	
	uint8_t mac5[6];
	esp_read_mac(mac5, ESP_MAC_BT);
	Serial.printf("[Bluetooth] Mac Address = %02X:%02X:%02X:%02X:%02X:%02X\r\n", mac5[0], mac5[1], mac5[2], mac5[3], mac5[4], mac5[5]);
	
	uint8_t mac6[6];
	esp_read_mac(mac6, ESP_MAC_ETH);
	Serial.printf("[Ethernet] Mac Address = %02X:%02X:%02X:%02X:%02X:%02X\r\n", mac6[0], mac6[1], mac6[2], mac6[3], mac6[4], mac6[5]);
}
 
void loop() {
	
}


결과 입니다.



이정도면, 사용되는 ESP32 가 어떤 상황인지 알 수 있을 것 같습니다.




6. RESET


소스를 ESP32 에 처음 업로드 하면, Serial Monitor 에 정보가 표시되지 않습니다.

이럴 때에는 "RESET" 버튼을 누르면 reboot 되면서 진행이 됩니다.



RESET 버튼을 누르고 reboot 이 되면, 부팅 시퀀스를 볼 수 있습니다.



MCU 가 arduino nano 와 완전 다른 차원이다 보니, 기본 스펙 파악도 중요하네요.



And
prev | 1 | 2 | 3 | next