'BLUETOOTH'에 해당되는 글 15건

  1. 2020.11.04 Hardware | Anker PowerConf 간단 사용기
  2. 2020.04.21 Hardware | ESP32 NTP Server 이용한 시간 맞추기
  3. 2020.04.18 Hardware | ESP32 Deep sleep 알아보기
  4. 2020.04.16 Hardware | ESP32 Cryptographic HW 가속 확인해 보기 2
  5. 2020.04.11 Hardware | EPS32 PWM 기능 확인해 보기
  6. 2020.04.09 Hardware | ESP32 의 internal sensor 확인해 보기 2
  7. 2020.04.08 Hardware | ESP32 의 Dual core 확인해 보기
  8. 2020.03.23 Hardware | ESP32 스펙 확인해 보기
  9. 2020.03.21 Hardware | ESP32 간단 사용기
  10. 2020.01.17 Hardware | bluetooth 모듈 SPP-C 사용해 보기

Hardware | Anker PowerConf 간단 사용기

|

1. 언텍트 시대


COVID-19 로 인하여, 업무 스타일이 많이 바뀌었습니다.

일하는 형태도, 굳이 사무실 출근이 아니라, 원격에서 근무하는 모습으로 바뀌어 가고 있죠.


글로벌 비지니스를 하는 회사들은 원래부터 그랬었지만, 이제는 일반 회사에서도, 고객들도 원격으로 일하는 시대가 도래 했습니다.

원격 미팅이 많아지는 요즈음, 회사에서 컨퍼런스 스피커 폰을 지급 받았습니다.


ANKER PowerConf





2. PowerConf


대략 사양은 다음과 같습니다.


- Bluetooth

- 360도 / 5m 범위로 목소리 커버

- 6개 마이크로 목소리 캐치

- 24시간 회의 지속 가능

- USB-C

- 회의 하면서 모바일 기기 충천도 가능

- 깔끔한 디자인과 가벼움 (?)

- 여행 케이스



Portable Bluetooth Speakerphone 이라고 합니다.



케이스 뒷면.



정식 명칭은 Anker - Anker PowerConf... UN Black Iteration 1 이라는군요.



케이스를 열면 캐링 케이스에 수납된 본체를 볼 수 있습니다.



구성품은 본체, 캐링 케이스, USB-C 케이블이 전부 입니다.





3. 연결


Power 버튼을 꾹~ 누르고 있으면, 근처의 PC 에서 Bluetooth 를 인식합니다. 연결은 one click 으로 끝났습니다. 이렇게 쉽게?



PC 와 연결 되면, 오른쪽 Bluetooth 인디케이터 LED 도 점등 됩니다.





4. 소리 조절


일단 PC 와 연결이 되면, PC 에서 소리 크기 조절은 먹히지 않고, 오로지 본체의 -/+ 버튼으로만 소리 조절이 됩니다.


살짝 불편할 수도 있겠지만, PC 에서는 소리를 줄인 상태로, PowerConf 에서도 같이 줄이거나 그 반대라고 한다면, 그 정도가 어디까지 알 수 없는 등, 기준이 없어집니다.


차라리, 한번 연결이 되면, 소리 음량 조절은 PC 에서 조작하지 않고, 오로지 본체에서만 따로 작동하는 방법도 좋아 보이는 군요.

아래 사진은, 소리를 1/3 정도로 키운 상태. 파란색으로 그 정도를 나타내 줍니다.



아래 사진은 mute (소리 소거) 상태. 전체를 빨간 색으로 알려 줍니다.



알아보기 쉽게, 조작 동영상 입니다.





5. 이어폰 연결


AUDIO 로 이어폰 연결해 봤습니다.



소리가 좋습니다. 렙탑에 연결 했을 때보다 소리가 훨~~~~~~~~~~~~~~~~~씬 좋습니다.

내장된 CODEC 이, 렙탑 내장 기본 코덱보다 좋은 것을 사용 했네요. 소리의 품질이 중후하며 선명합니다.



블루투스 무선이라는 장점으로 이어폰만 연결하면 선이 간결하고, 놔둘 위치를 쉽게 바꿀 수 있어서 편합니다.

요즈음은 PowerConf 를 이어폰 용으로 주로 사용하고 있네요.


예전에 Jabra 510 시리즈를 사용해본 경험으로 비교해 보자면, 음질이나 Bluetooth 무선, 배터리 내장, USB 로 다른 기기 충전 가능 등,

비교 불가 입니다.


이쪽 관련 기기는 전동적으로 Jabra 였지만, 이제는 아닌것 같습니다.



Update - 20210113


배터리 충전 상황을 확인하고 싶을 경우에는 제어판에서 연결 상태를 확인하면 충전량 확인이 가능합니다.



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

Hardware | ESP32 간단 사용기

|

일전에 ESP-01 (ESP8266) 을 가지고 IoT 환경을 꾸며 봤습니다.


* Hardware | CO2 센서인 MH-Z14A 를 활용해 보자
    - https://chocoball.tistory.com/entry/Hardware-CO2-sensor-MH-Z14A


ESP-01 은, WiFi 모듈로는 초기형이고, 그 이후에 업그레이드 된 모듈들이 많이 출시 되었습니다.

그 다음으로 많이 사용하는 WiFi 모듈은 "ESP32" 인 듯 합니다.




1. ESP32


구매합니다.


* ESP32 ESP-32 ESP32S ESP-32S CP2102 Wireless WiFi Bluetooth Development Board Micro USB Dual Core Power Amplifier Filter Module
    - https://www.aliexpress.com/item/32928267626.html


잘 도착 했습니다.





2. 외형


Arduino nano 의 경우, MCU 가 ATmega328 였지만, ESP32 는 MCU + WiFi + Bluetooth + ... 가 chip 하나에 모두 들어간 형태 입니다.



ESP-WROOM-32 라고 적힌 철판 밑에 MCU 가 자리잡고 있을 듯 합니다.



USB interface 는 Silicon Labs 사의 CP2102 이군요. WiFi 접근에 따로 FTDI 같은 어뎁터를 경유할 필요가 없습니다.



뒷면에는 ESP32 DEVKIT V1 이라고 적혀 있네요.




3. MCU


* ESP32

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



MCU 의 정식 명칭은 "ESP32-DOWDQ6" 라고 확인이 되었습니다. (Arduino IDE 에서 컴파일 할 때 확인 가능)


MCU 의 logic diagram 입니다. 몇 가지 재미있는 부분들이 보이네요. 센서 내장이라던지... (센서에 환장한 人)



이 chip 의 naming 을 통해서도 spec. 을 알 수 있습니다.



데이터 쉬트 입니다.

esp32_datasheet_en.pdf


간단히 ESP8266 (ESP-01) 과 비교 테이블을 만들어 봤습니다.


|------------------------------------------------------------------------------------|
|                       | ESP8266                     | ESP32                        |
|------------------------------------------------------------------------------------|
| release Year          | 2014                        | 2016                         |
| Processor             | Tensilica L106 32-bit       | Xtensa Dual-core 32-bit LX6  |
|                       | single core micro controller| microprocessor with 600 DMIPS|
| Typical Frequency     | 80 MHz                      | 160 MHz                      |
| Co-processor          | no                          | ULP                          |
| ROM                   | no                          | 448 kB                       |
| SRAM                  | 160kB                       | 520 kB                       |
| RTC RAM               | 768 Bytes                   | 8kB slow + 8kB fast          |
| QSPI flash/SRAM       | up to 1 x 16 MB             | up to 4 x 16 MB              |
| GPIOs                 | 17                          | 36                           |
| Wi-Fi                 | HT20                        | HT40                         |
| Bluetooth             | no                          | Bluetooth 4.2 and BLE        |
| Ethernet              | no                          | 10/100 Mbps                  |
| ADC                   | 10 bit                      | 12 bit                       |
| DAC                   | no                          | 2 x 8 bit                    |
| Touch sensor          | no                          | 10                           |
| Temperature Sensor    | no                          | yes                          |
| Security              | no                          | Secure boot Flash encryption |
|                       |                             | 1024-bit OTP                 |
| Crypto                | no                          | AES, SHA-2, RSA, ECC, RNG    |
| SPI                   | 2                           | 4                            |
| I2C                   | 1 (soft)                    | 2                            |
| I2S                   | 2                           | 2                            |
| UART                  | 2 (1 1/2 actually)          | 3                            |
| ADC                   | 1 (10-bit)                  | 18 (12-bit)                  |
| DAC                   | no                          | 2 (8-bit)                    |
| PWM Pins              | 8 Software                  | 1 Hardware / 16 software     |
| SDMMC                 | no                          | yes                          |
| RMT (remote control)  | no                          | yes                          |
| Temperature sensor    | no                          | yes                          |
| Hall sensor           | no                          | yes                          |
| Low Power Consumption | 20uA                        | 10uA deep sleep              |
| Power supply          | 2.5V to 3.6V                | 2.3V to 3.6V                 |
|------------------------------------------------------------------------------------|


생산 업체가 이야기하는 가장 큰 특장점은 아래 5 가지로 정리할 수 있겠습니다.


- Dual-core 32-bit microprocessor

- 2.4 GHz Wi-Fi and Bluetooth combo chip
- TSMC low power 40nm lithography technology
- Best power performance and RF performance
- Robustness, versatility and reliability


Pin out 정보 입니다. 기존 arduino nano 나 ESP-01 과는 차원이 다른 구성입니다.



이거 하나면 왠만한거 다 할 수 있겠네요.




4. Arduino IDE - 드라이버 설치


코딩을 하고 동작을 시키려면 Arduino IDE 등을 이용해서 프로그램을 업로드 할 수 있습니다. 기존 arduino 와 완전히 동일하죠.

다만, Arduino IDE 의 기본 기기나 라이브러리에 등록되어 있지 않으므로, 새로이 등록시켜주는 작업이 필요합니다.


위에서 잠깐 언급한 대로, USB interface 는 Silicon Labs 의 CP2102 이므로, 해당 드라이버를 설치해 줘야 합니다.

Windows 10 에서는 USB 를 연결하자 마자 알아서 설치해 줍니다.


예전에 Serial Adapter 처음 사용할 때, 이 등록절차를 소개한 적이 있습니다. 아래 글을 참고해 주세요.


* Hardware | FTDI Serial Adapter 를 사용해 보자
    - https://chocoball.tistory.com/entry/Hardware-FTDI-FT232RL-using


드라이버가 정상적으로 설치되면, 아래와 같이 포트가 인식됩니다.





5. Arduino IDE - Board Manager


Arduino IDE 에서 보드를 등록하고, 관련 라이브러리를 설치해야 합니다.
우선 File > Preferences 로 갑니다.


Additional Board Manager URLs 에 ESP32 에 관련한 URL 을 등록 합니다.


https://dl.espressif.com/dl/package_esp32_index.json



그러면, Tools > Board > Boards Manager 에서 관련된 라이브러리를 설치할 수 있게 됩니다.



검색 줄에 esp32 라고 검색하면 esp32 by Espressif Systems 가 뜹니다. 인스톨 해 줍니다.



그러면, Board 선택에서 ESP32 보드가 보이고, 선택할 수 있게 됩니다.



Upload Speed 나 Flash Frequency 등은 나중에 차차 수정하기로 하고, 아까 CP2102 가 할당된 포트를 지정합니다.



이제 준비는 끝났습니다.




6. Blink


Arduino 의 "Hello World" 라고 할 수 있는 Blink 를 실행해 봅니다.


File > Examples > 01.Basics > Blink 소스를 업로드 해 줍니다.


/*
  Blink

  Turns an LED on for one second, then off for one second, repeatedly.

  Most Arduinos have an on-board LED you can control. On the UNO, MEGA and ZERO
  it is attached to digital pin 13, on MKR1000 on pin 6. LED_BUILTIN is set to
  the correct LED pin independent of which board is used.
  If you want to know what pin the on-board LED is connected to on your Arduino
  model, check the Technical Specs of your board at:
  https://www.arduino.cc/en/Main/Products

  modified 8 May 2014
  by Scott Fitzgerald
  modified 2 Sep 2016
  by Arturo Guadalupi
  modified 8 Sep 2016
  by Colby Newman

  This example code is in the public domain.

  http://www.arduino.cc/en/Tutorial/Blink
*/

// the setup function runs once when you press reset or power the board
void setup() {
  // initialize digital pin LED_BUILTIN as an output.
  pinMode(LED_BUILTIN, OUTPUT);
}

// the loop function runs over and over again forever
void loop() {
  digitalWrite(LED_BUILTIN, HIGH);   // turn the LED on (HIGH is the voltage level)
  delay(1000);                       // wait for a second
  digitalWrite(LED_BUILTIN, LOW);    // turn the LED off by making the voltage LOW
  delay(1000);                       // wait for a second
}


Arduino 기기가 아님에도 불구하고, "LED_BUILTIN" 으로 지정하면, breakout board 상의 LED 를 점등시켜 줍니다.



간단하게 성공해버려 조금 허탈한 감이 있습니다.




7. WiFiScan


MCU 자체적으로 WiFi 까지 커버하는 SoC 인지라, WiFi 도 동작 하는지 확인해 봅시다.
지금까지의 작업으로 라이브러리 및 Examples 소스도 인스톨 되어 있으니, WiFiScan 이라는 소스를 올려 봤습니다.

File > Examples > WiFi > WiFiScan



ESP-01 을 사용할 때에는, AT command 를 사용해서 직접 컨트롤 했지만, ESP32 는 라이브러리 함수만으로 모든게 컨트롤 가능해 보입니다.



소스가 엄청 짧습니다.

컴파일 끝나고 ESP32 에 업로드 할 때, ESP32 기기와 관련된 정보를 뿌려줘서 캡춰해 봤습니다.


동작 주파수가 240MHz 도 가능하고, 외장 Flash 크기가 4MB 군요!


esptool.py v2.6
Serial port COM8
Connecting.....
Chip is ESP32D0WDQ6 (revision 1)
Features: WiFi, BT, Dual Core, 240MHz, VRef calibration in efuse, Coding Scheme None
MAC: 24:6f:28:a1:af:8c
Uploading stub...
Running stub...
Stub running...
Changing baud rate to 921600
Changed.
Configuring flash size...
Auto-detected Flash size: 4MB
Compressed 8192 bytes to 47...

Writing at 0x0000e000... (100 %)
Wrote 8192 bytes (47 compressed) at 0x0000e000 in 0.0 seconds (effective 5461.3 kbit/s)...
Hash of data verified.
Compressed 15856 bytes to 10276...

Writing at 0x00001000... (100 %)
Wrote 15856 bytes (10276 compressed) at 0x00001000 in 0.1 seconds (effective 953.7 kbit/s)...
Hash of data verified.
Compressed 623776 bytes to 372912...

Writing at 0x00010000... (4 %)
Writing at 0x00014000... (8 %)
Writing at 0x00018000... (13 %)
Writing at 0x0001c000... (17 %)
Writing at 0x00020000... (21 %)
Writing at 0x00024000... (26 %)
Writing at 0x00028000... (30 %)
Writing at 0x0002c000... (34 %)
Writing at 0x00030000... (39 %)
Writing at 0x00034000... (43 %)
Writing at 0x00038000... (47 %)
Writing at 0x0003c000... (52 %)
Writing at 0x00040000... (56 %)
Writing at 0x00044000... (60 %)
Writing at 0x00048000... (65 %)
Writing at 0x0004c000... (69 %)
Writing at 0x00050000... (73 %)
Writing at 0x00054000... (78 %)
Writing at 0x00058000... (82 %)
Writing at 0x0005c000... (86 %)
Writing at 0x00060000... (91 %)
Writing at 0x00064000... (95 %)
Writing at 0x00068000... (100 %)
Wrote 623776 bytes (372912 compressed) at 0x00010000 in 5.3 seconds (effective 933.3 kbit/s)...
Hash of data verified.
Compressed 3072 bytes to 128...

Writing at 0x00008000... (100 %)
Wrote 3072 bytes (128 compressed) at 0x00008000 in 0.0 seconds (effective 2234.2 kbit/s)...
Hash of data verified.

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


Serial Monitor 로 확인해 보니, 아래와 같이 주변 access point 들을 보여 줍니다. 음... 넘 쉬운데?!!!





8. 자, 다음...


Dual-core 에 여러 센서까지 복잡하게 갖춘 ESP32 지만, 강력한 라이브러리로 인하여, 쉽게 이용할 수 있다는 것에 놀랐습니다.

또한, WiFi / Bluetooth 가 MCU 에서 지원하니, 따로 모듈을 연결할 필요가 없어, IoT 구현 시, 회로가 간단해 지겠네요.


추가 기능들을 가지고 있으니, 다음 편들에서는 아래 내용들에 대해 확인해 보도록 하겠습니다.


 - Dual-core

 - Sleep Modes
 - OTA Updates
 - OTA Web Updater
 - NTP Server
 - Temp Sensor
 - Touch Sensor
 - Hall Sensor


And

Hardware | bluetooth 모듈 SPP-C 사용해 보기

|

Bluetooth 모듈에 꽂혀 꽃혀, 한꺼번에 구입한 모듈들의 마지막 모듈인 SPP-C 확인 포스트 입니다.

지금까지 확인해 본 Bluetooth 모듀에 대해서는 아래 글을 참고해 보세요.


* Hardware | bluetooth 모듈 HC-06 / HC-05 사용해 보기 - 2

- https://chocoball.tistory.com/entry/Hardware-bluetooth-HC06-HC05-2


* Hardware | bluetooth 모듈 HC-06 / HC-05 사용해 보기 - 1

https://chocoball.tistory.com/entry/Hardware-bluetooth-HC06-HC05-1




1. SPP-C


이름도 생소한 SPP-C Bluetooth 모듈입니다.

구입처는 아래 링크에서 구입. 일반 모듈 치고는 3천원 정도로 고가네요.


* SPP-C Bluetooth serial pass-through module wireless serial communication from machine Wireless SPPC Replace HC-05 HC-06

- https://www.aliexpress.com/item/32755550889.html



사용된 main chip 은 Beken 이라는 중국 회사 제품 입니다.


* BK3231

BKDatasheet.pdf

SPP-CA HardwareGuide_chn.pdfSPP.pdf

SPP.pdf


외형은 다음과 같이 생겼어요.



사진에서 볼 수 있 듯, 사용된 breakout board 는 HC-05 / 06 과 동일한 ZS-040 이 사용 되었습니다.




2. 간단 구동


FTDI 로 연결하여 Arduino IDE 의 Serial Monitor 를 통해, AT command 로 상태 확인을 해보겠습니다.



이렇게 계속 LED 가 깜빡이면, AT command mode 라고 하네요.

Paring 이 되면, LED 가 계속 켜져 있습니다.



아래는 간단한 AT command 의 결과 입니다.

HC-05 / 06 과 다른 점은, AT 명령어 끝에 물음표 ( ? ) 를 넣지 않습니다.



AT

ready 상태 확인


AT+RESET

상태 reset


AT+VERSION

firmware version 확인


AT+LADDR

할당된 주소 표시


AT+NAME

기기 확인용 이름 확인하거나 설정


AT+ROLE

Master / Slave 확인하거나 설정


AT+PIN

Paring 시 사용 될 비밀번호 확인하거나 설정


AT+BAUD

Paring 시 사용 될 baud rate 확인하거나 설정


AT+HELP

특이하게 HELP 명령어를 지원합니다. 어떤 명령어들이 준비되어 있는지 알 수 있으니 좋네요.





3. Windows 10 과 연동


HC-05 / 06 에서 했던 OS 와 연동시켜 봅니다.



Windows 10 에서 기기를 찾을 수 있습니다.



Paring 을 위한 password 를 넣습니다. 아까 AT command 로 확인한 "1234" 겠죠?



일반 Bluetooth 기기처럼 쉽게 연결이 됩니다. 장치관리자에서 기기 등록이 완료됩니다.



연결된 Bluetooth 가, 그 모듈이 맞는지 주소도 확인해 봅니다.



Windows 에서는 COM11 로 연결되었군요.



Putty 를 이용해 접근해 봅니다. 초기 Speed Baud rate 는 9600 입니다.



Serial Monitor (FTDI 연결) 와 Putty (Serial) 접속 - 각각 다른 접근을 통해, paring 통신이 가능한지 확인해 봅니다.



서로 연결이 문제없이 되고, 문자 전송으로 통신 연결을 확인 할 수 있습니다.

동영상 첨부합니다.



HC-05/06 과 다른 점은, pairing 연결/해제에 대한 상태 및 상대 주소도 보여줍니다.


Paring 성공

+CONNECTING<<

CONNECTED


Paring 해제

DISC:SUCCESS

+READY

+PAIRABLE





4. Master / Slave 연동 준비


HC-05/06 에서 해 봤던, Master/Slave 연동을 시험해 보기로 합니다.



우선 HC-05/06 에서 통신 속도를 38400 baud rate 로 맞춰서 진행했으니, 동일하게 설정합니다.

AT 명령어는, "AT+BAUD6" 입니다.



Serial Monitor 에서 명령어 실행 후, baud rate 를 바꿔 확인하면, 정상적으로 설정 된 것을 확인.



SPP-C 를 Slave 로 이용시, 가지고 있는 주소를 알아야 Master 에서 직접 연결이 가능하므로, 주소를 따 놓습니다.

그 주소를 HC-05 Master 에 등록해 줍니다.




5. Master / Slave 연동 연결


연결은 한번 해봤던 회로를 그대로 사용.


   SPP-C  | Arduino Nano
-------------------------
    TXD   |      D10
    RXD   |      D11
-------------------------
          |     POWER
-------------------------
    VCC   |      3.3V
    GND   |      GND
-------------------------
  SWITCH  |      D2
 LED+220Ω |      D8
-------------------------


회로도도 동일.



아래와 같이 배선. 얼핏 보기엔 복잡하지만, LED 와 스위치, 그리고 TX/RX 를 연결해 주면 됩니다.



다른 분들은 쉽게 하는것 같은데, arduino 에서 전원을 끌어다 쓰면 정상동작 하지 않았습니다.

외부전원 - MB102 를 사용해야 정상 동작했습니다.



동작 확인 동영상 입니다.

Arduino 에 들어간 소스는 tactile switch 가 눌리면 Master / Slave 에 신호를 보내고,

상대 Slave / Master 에서 신호를 받으면 LED 를 high 로 만드는 소스 입니다.



소스는 이전 포스트인 아래 글에 올려 놨습니다.


    * Hardware | bluetooth 모듈 HC-06 / HC-05 사용해 보기 - 2

- https://chocoball.tistory.com/entry/Hardware-bluetooth-HC06-HC05-2




5. Master / Slave 모드 변경


검색 해보면, SPP-C 에 사용된 BK3231 는 Slave 뿐만 아니라, Master 로도 사용이 가능합니다.

"AT+ROLE1" 명령어로 Master 로 변경되어야 하나, command 결과가 OK 라 할지라도 모드 변경이 되지 않습니다.



메뉴얼을 찾아 봤습니다.



하드웨어적으로 Slave only 가 될 수도 있다고 하네요.

좀더 찾아 봤습니다. BC04-A 이지만, BC04-B 메뉴얼에 보면, PIO(4)PIO(5) 를 이용해서 모드 변경이 가능하다 합니다.



PIO(4) 를 3.3V 에 연결하면 software 변경 모드로 온다 합니다. 이렇게 하면 AT command 로 조정 가능해 보입니다.

그렇게 하면 PIO(5) 는 건들지 않아도 된다고 하네요.



27번핀이 PIO(4) 인 것이군요.


BC04-B Technical specification.pdf

BC04-B_AT_Command.pdf

BK3231_ARM968E-S.pdf

BLK-MD-BC04-B_AT-COMMANDS.pdf

DS_IM130614001_Serial_Port_BLE_Module_Master_Slave_HM-10.pdf


단, 좀 확신을 가질 수 없는게, 명확히 BC04-A 레이아웃에도 적용이 되는지 입니다.

여러 사진들을 찾아 봤으나, BK3231 이 올라간 그림에서 PIO(4) 는 여기닷! 이라고 찍혀 있는 사진이 없었습니다.



이렇게 보면, Pin 구성이 많이 다른것 같기도 하고...





6. 접점 변경


일단 BC04-B 기준으로 접점 조정을 해보기로 합니다.



배를 갈라주고...



저 노란색 화살표의 제일 오른쪽이 PIO(4) 인데, 일단 납땜이 되어 있습니다.

Slave 고정되어 있는 현재의 상태를 변경해줘야 하니, 땜 접점을 없애 주기로 합니다.



열풍기가 있으면 한방이겠지만... ㅠ.ㅠ

토스트기에 넣고 구우면서 핀셋으로 흔들어 봅니다. 효과 없군요.



RX/TX 부분이 가장 멀리 떨어져 있으니, 여기서부터 납 제거 및 보드를 살짝씩 들어 올려서 분리 시도 합니다.



잘 떨어졌는데, 위 사진의 화살표 보이는 것 처럼 동판도 들려버렸습니다. 아...



캡톤 테이프 성애자인 저는, 막아야 할 27 pin 및 혹시라도 접점이 생길것 같은 부분을 커버해 줍니다.



27 pin 을 방어한 체로, 다시 납땜.



그리고 FTDI 에 연결.

반응이 없습니다..............


FTDI 연결 모듈에 들오지 않은 불이 하나 더 들어 옵니다. 어딘가 쇼트가 되었거나 기판 (동판) 이 망가진 듯.

27 pin 을 다시 납땜 해서 접점을 만들어 줘도 동일 현상.


확실하게 망가졌네요. ㅠㅠ


SPP-C 를 Master 화 시키는 것은 실패했습니다.
오기가 발동하여, 동일한거 하나 더 구입해서 깔끔하게 다시 작업해 볼까 했습니다만,
다른 할것도 많고, 실제 구현때는 더 좋은 모듈을 사용할 것이기에 여기까지만 해보기로 타협합니다.


And
prev | 1 | 2 | next