こんばんは。
いきなり余談ですが、つい昨日、2017/8/1 に GitHub の Arduino core for ESP32 が大幅修正されました。
ようやく WiFiClientSecure ライブラリがまともに動くようになりました。
そして、main.cpp のスタックサイズも 8192 となり、ESP32 ( ESP-WROOM-32 )のマルチタスク(デュアルコア)で SSLページの Web GET リクエストが問題無く動作するようになりました。
ただ、今、頻繁に更新されていますので、安定するまでしばらくダウンロードは待った方が良いかもしれません。
また、Serial.begin クラスが2重使用できなくなりましたので、当方自作の以下のライブラリも修正しました。
ESP32_SD_UTF8toSJIS beta ver 1.21
ESP32_SD_ShinonomeFNT beta ver 1.21
さて、本題に戻りまして、今回は前回の記事の続きです。
以前紹介した以下の記事で、ESP32 ( ESP-WROOM-32 ) ガジェットをマルチタスク(デュアルコア)で動かしてみたいと思います。
ESP32 と 有機EL SSD1331 で Yahoo News 、 天気予報 、 NTP 時計 Wi-FI ガジェットを作ってみた
では、早速以下の動画をご覧ください。
いかがでしょうか。
後ろに見えているのは、Arduino IDE のシリアルモニターです。
時計表示のスクロールや、Yahoo! Japan RSS ニュースのスクロールも停止せずに、別の CPU で動かしている SSL ページの GETリクエストが出来ていますね。
しかも、前回と異なるのは、ニュース記事と天気予報と NTP時刻取得など、Web から3つの情報を GET していることです。
電子工作レベルでこんな感じで安定して SSL ページをGET できるなんて、夢のようですね。
Arduino core for ESP32 も大幅更新されたため、ガッツリ安定動作です。
前回の記事では、有機EL ( OLED )ディスプレイのSPI通信をマルチタスクの core 0 で動作させて、Web の SSL ページ記事への GET リクエストはメインループの core 1 で動作させていました。
記事取得は1つでした。
今回のポイントは、ニュース記事と天気予報の2つの SSLページ GET と、UDP を使った NTPサーバー 時刻取得など、複数の記事取得をマルチタスクで行ったことです。
Arduino core for ESP32 の WiFiUdp ライブラリと、Arduino 標準の TimeLib ライブラリを使う場合は、うまく CPU core を分けてやらないと、HSPI接続 の OLED が一時停止してしまいます。
では、今回はその方法を紹介します。
この記事および自作ソースコードの公開について、Yahoo! Japan さんにお問い合わせして、趣味や研究範囲と判断でき、問題無いとの回答を得ております。 (2017/8/11)
最新版 Arduino core for ESP32 のインストール
先にも述べましたが、2017/8/1 以降、GitHub の Arduino core for ESP32 が大幅アップデートされました。
WiFiClientSecure ライブラリも正常に動くようになりましたので、最新版をインストールしてください。
インストール方法は以下のページを参照してください。
※get.exe を実行するだけではダメです。ZIPファイルを新たにダウンロードして再インストールしてください。
Arduino core for the ESP32 のインストール方法
使用するもの
前回の記事と同様です。
ESP32 ( ESP-WROOM-32 )開発ボード
●ESPr Developer 32 ( スイッチサイエンス製)
当ブログおすすめボードです。
ESPr Developer 32 ( スイッチサイエンス製 ) を使ってみました
●ESP32-DevKitC ( Espressif 製)
本家 Espressif社の開発ボードです。
フルカラー有機EL ( OLED ) SSD1331 SPIモジュール
SparkFun マイクロSDカードスロット・ピッチ変換基板
SparkFun マイクロSDカードスロット・ピッチ変換基板
micro SDHC カード
サンハヤト SAD-101 ニューブレッドボード
ESPr Developer 32 でも使えるお勧めブレッドボードです。
固定抵抗10kΩ程度×2
micro SDカードスロットのプルアップ用です。
ジャンパワイヤー、WiFi環境、パソコン、USBケーブル等
使うもの、接続、ライブラリのインストール等
以下の記事を参考にして、最新版ライブラリのインストール、フォントのインストールを済ませておいてください。
ESP32 マルチタスク(デュアルコア)で、電光掲示板スクロールを止めずに、別のCPUで Web GET できました
それぞれのバージョンは以下の通りです。
【自作ライブラリ】
ESP32_SD_SSD1331_Gadgets ( beta ver 1.1 )
ESP32_SD_ShinonomeFNT ( beta ver 1.21 )
ESP32_SD_UTF8toSJIS ( beta ver 1.21 )
ESP32_SSD1331 ( beta ver 1.3 )
ESP32_WebGet ( beta ver 1.1 )
【Arduino 標準ライブラリ】
Time ライブラリ ( ver 1.5 )
天気予報自作フォントのインストールは以下の記事を参照してください。
ESP32 と 有機EL SSD1331 で Yahoo News 、 天気予報 、 NTP 時計 Wi-FI ガジェットを作ってみた
また、フォントを修正したい場合は以下の記事を参照してください。
天気予報を自作フォントで表示してみた ( ESP32 , OLED SSD1331 )
スケッチの入力
では、以下のスケッチを入力してください。
前回の記事と重複しているところは省きます。
【ソースコード】 (※無保証 ※PCの場合、ダブルクリックすればコード全体を選択できます)
#include "ESP32_SD_SSD1331_Gadgets.h" //beta ver 1.1 #include "ESP32_SD_ShinonomeFNT.h" //beta ver 1.21 #include "ESP32_SD_UTF8toSJIS.h" //beta ver 1.21 const char* ssid = "xxxx"; //ご自分のルーターのSSIDに書き換えてください。 const char* password = "xxxx"; //ご自分のルーターのパスワードに書き換えてください。 const char* UTF8SJIS_file = "/font/Utf8Sjis.tbl"; //UTF8 Shift_JIS 変換テーブルファイル名を記載しておく const char* Shino_Zen_Font_file = "/font/shnmk16.bdf"; //全角フォントファイル名を定義 const char* Shino_Half_Font_file = "/font/shnm8x16.bdf"; //半角フォントファイル名を定義 const char* MyFont_file = "/font/MyFont.fnt"; //自作フォントファイル名を定義 const char* Yahoo_rootca_file = "/root_ca/yahoo.cer"; //Yahoo! Japan RSS ルート証明書ファイル const uint8_t CS_SD = 5; //SD card CS ( Chip Select ) const uint8_t SCLK_OLED = 14; //SCLK const uint8_t MOSI_OLED = 13; //MOSI (Master Output Slave Input) const uint8_t MISO_OLED = 12; //これは実際は使っていない。MISO (Master Input Slave Output) const uint8_t CS_OLED = 15; const uint8_t DC_OLED = 16; //OLED DC(Data/Command) const uint8_t RST_OLED = 4; //OLED Reset ESP32_SD_SSD1331_Gadgets ESSG; ESP32_SD_UTF8toSJIS u8ts; ESP32_SSD1331 _ssd1331(SCLK_OLED, MISO_OLED, MOSI_OLED, CS_OLED, DC_OLED, RST_OLED); ESP32_SD_ShinonomeFNT _SFR(CS_SD, 24000000); ESP32_WebGet _EWG; uint8_t news_sj_txt[1024]; //Shift_JIS コード文字列を格納 uint16_t news_sj_length; //Shift_JIS コード文字列長 //-----ニュース記事文字列スクロール変数の初期化-------- uint16_t Scrolle_speed = 10; //文字列スクロールインターバル時間 //-----NTP時刻GET設定--------- uint32_t NTP_LastTime = 0; //-----Yahoo記事取得引数初期化------------------------- uint64_t NewsGetLastTime = 0; uint64_t WeatherGetLastTime = 0; bool News_first_get = true; bool Weather_first_get = true; bool News_get = false; bool Weather_get = false; String weather_str; portTickType xLastWakeWebGetTime1; //マルチタスク時間カウント //*****************セットアップ****************************** void setup() { Serial.begin(115200); _EWG.EWG_AP_Connect(ssid, password); //Wi-Fi ルーターと接続 delay(1000); _ssd1331.SSD1331_Init(); //OLED SSD1331 初期化 _SFR.SD_Shinonome_Init3F(UTF8SJIS_file, Shino_Half_Font_file, Shino_Zen_Font_file); //ライブラリ初期化。3ファイル同時に開く ESSG.Gadgets_MyFont_Init(MyFont_file); //自作フォント初期化 delay(10); _EWG.EWG_NTP_TimeLib_init(9, "time.windows.com"); //NTPサーバー取得初期化 _EWG.NTP_OtherServerSelect(9); //NTPサーバーと接続できなかった場合、他のNTPサーバーと接続できるか試す関数 TaskHandle_t th; //マルチタスクハンドル定義 xTaskCreatePinnedToCore(Task1, "Task1", 4096, NULL, 5, &th, 0); //マルチタスク実行 xLastWakeWebGetTime1 = xTaskGetTickCount(); //マルチタスク時間カウント代入 NewsGetLastTime = millis(); WeatherGetLastTime = millis(); } //************* メインループ **************************************** void loop() { YahooNewsGET(0, 180000, 0, 7, 0); //180秒毎に天気取得 YahooWeatherGET(48, 180000); //180秒毎に天気取得 _EWG.NTP_Get_Interval(180000); //180秒毎にNTPサーバーから時刻取得 } //************* マルチタスク **************************************** void Task1(void *pvParameters){ while(1){ ESSG.Scroll_1_line(0, 0, 0, 7, 0, Scrolle_speed, news_sj_txt, news_sj_length, &News_get); ESSG.ShinonomeClock_YMD(0, 16, 3, 3, 3); //東雲フォント年月日表示 ESSG.MyFontClock_Weekday(80, 16, 7, 7, 3); //自作フォント曜日表示 ESSG.Shinonome_Sec_Clock(80, 32, 'H', 'V', 0, 0, 15, 7, 0, 1); //東雲フォント秒表示 ESSG.MyFont_HM_Clock(0, 32, 'H', 'V', 'H', 'V', 0, 0, 1, 1, 50, 7, 0, 1); //自作フォント時分表示 if(Weather_get){ //サーバーから天気予報取得できたら、OLED表示を更新 ESSG.YahooJ_Weather_TodayTomorrow(48, weather_str); Weather_get = false; } } } //************** Yahoo RSS ニュースガジェット ************************ void YahooNewsGET(uint8_t y0, uint32_t get_interval, uint8_t Red, uint8_t Green, uint8_t Blue){ if((News_first_get == true) || ((millis() - NewsGetLastTime) > get_interval)){ char web_get_time[6]; sprintf(web_get_time, "%02d:%02d", hour(), minute()); //ゼロを空白で埋める場合は%2dとする String news_str = "◆ " + String(web_get_time) + " "; char root_ca[2048]; ESSG.Root_CA_SDcard_Read(Yahoo_rootca_file, root_ca); //SDカードに保存してあるルート証明書取得 news_str += _EWG.EWG_https_Web_Get(root_ca, "news.yahoo.co.jp", "/rss/topics/top-picks.xml", '\n', "</rss>", "<title>", "</title>", "◆ "); Serial.print("News Get = "); Serial.println( news_str ); Serial.flush(); //シリアル出力が終わるまで待つ news_sj_length = u8ts.UTF8_to_SJIS(news_str, news_sj_txt); NewsGetLastTime = millis(); News_first_get = false; News_get = true; } } //************** Yahoo RSS 天気予報ガジェット ************************* void YahooWeatherGET(uint8_t y0, uint32_t get_interval){ if((Weather_first_get == true) || ((millis() - WeatherGetLastTime) > get_interval)){ char root_ca[2048]; ESSG.Root_CA_SDcard_Read(Yahoo_rootca_file, root_ca); //SDカードに保存してあるルート証明書取得 //東京の天気予報 weather_str = _EWG.EWG_https_Web_Get(root_ca, "rss-weather.yahoo.co.jp", "/rss/days/46.xml", '>', "</rss", "】 ", " - ", "|"); Serial.print("Weather forecast = "); Serial.println(weather_str); Serial.flush(); //シリアル出力が終わるまで待つ WeatherGetLastTime = millis(); Weather_get = true; Weather_first_get = false; } }
【解説】
●1-3行:
先にも述べた通り、2017/8/1から Arduino core for ESP32 が大幅アップデートされました。
それにより、Serial.beginクラスも2重使用できなくなりましたので、以下のライブラリは最新の beta ver 1.21 を使用してください。
ESP32_SD_ShinonomeFNT ( beta ver 1.21 )
ESP32_SD_UTF8toSJIS ( beta ver 1.21 )
このライブラリは ESP32_SD_SSD1331_Gadgets でインクルードされていて、無くても良いのですが、あえてここで明示的にインクルードしておきます。
●12行:
micro SD カードに保存してある、Yahoo! Japan RSS サイトの SSL ルート証明書ファイル名です。
●34行:
ニュース記事スクロールインターバル時間はミリセコンド単位で決めます。
10ms くらいがちょうど良いと思います。
●48行:
ESP32 に搭載してある、FreeRTOS の経過時間をカウントするものです。
Tick という単位でカウントしています。
●53行:
自作の ESP32_Web_Get ライブラリのクラスで、ここでWi-Fiルータと接続しています。
このクラス内で、Serial.begin(115200); を使用しています。
●57行:
ここでフォントファイルを3つ開いています。
ESP32 ( ESP-WROOM-32 )では、1タスク内で同時に開けるファイル数は4つまでです。
●59行:
ここで自作フォントファイルを開いていますので、同時に開くファイル合計は4つになります。
後は、Yahoo! Japan RSS のルート証明書を開く必要がありますが、これはデュアルコアの別タスクになります。
●62-63行:
ここで、NTPサーバーから時刻を取得しています。
もし、time.windows.com から取得できなかった場合、他の NTP サーバーから時刻を取得するようにしました。
Arduino 標準の Time ライブラリでは、時刻セットにsetSyncProvider 関数をよく使いますが、これを使うと、自動で定期的にタイムをセットする時に、core 0 のループが一時中断してしまいます。
これの原因は突き止めておらず、良く分からないのですが、setSyncProvider関数を使わずに、setTime関数を使って NTP時刻をセットすれば、ユーザーで自由にタスクを選べます。
これは、77行でセットしています。
●65-66行:
ESP32 でマルチタスク(デュアルコア)で動かす、FreeRTOS 関数です。
80-93行の関数がメインループとは別のCPU で実行されます。
このタスクは core 0 、メインloop は core 1 です。
要するに、有機EL ( OLED )表示の SPI制御は core 0 で、Web記事 GET や NTP サーバー時刻取得は core 1 です。
●68行:
ここで、FreeRTOS の起動からの時間(Tickカウント)を代入します。
●74-78行:
メインloop 内では、WiFiClientSecure ライブラリで、Web記事を GET したり、WiFiUdp ライブラリで NTPサーバーから時刻を取得したりする関数を置きます。
●80-93行:
ここでは、マルチタスク(デュアルコア)の core 0 のループです。
82-86行は自作ライブラリESP32_SD_SSD1331_Gadgets からの関数群です。
カラーは赤、緑、青の三原色を混ぜて作ります。
256 色で指定します。
赤色 ( 0-7 )
緑色 ( 0-7 )
青色 ( 0-3 )
詳しい説明は省きますが、値をいろいろ変えてみて試してください。
Scroll_1_line(Y座標 , 番号 , 赤 , 緑 , 青 , インターバル , S-jisコード)
ShinonomeClock_YMD( X座標 , Y座標 , 赤 , 緑 , 青 )
MyFontClock_Weekday( X座標 , Y座標 , 赤 , 緑 , 青 )
Shinonome_Sec_Clock( X座標 , Y座標 , ‘V’ or ‘H’ , ‘V’ or ’H’ , 0 or 1 , 0 or 1 , 速さ , 赤 , 緑 , 青 )
MyFont_HM_Clock( X座標 , Y座標 , ‘V’ or ‘H’ , ‘V’ or ’H’ , ‘V’ or ‘H’ , ‘V’ or ’H’ , 0 or 1 , 0 or 1 , 0 or 1 , 0 or 1 ,速さ , 赤 , 緑 , 青 )
その他、以下の記事も参照してみてください。
ESP32 と 有機EL SSD1331 で Yahoo News 、 天気予報 、 NTP 時計 Wi-FI ガジェットを作ってみた
また、88-91行で、Yahoo! Japan RSS の天気予報から文字列抽出したものを、自作フォントに変換して OLED ディスプレイに表示させています。
●95-112行:
Yahoo! Japan RSS サイトからトップニューストピックスを取得する関数です。
97-99行で、取得時刻を文字列に変換して、頭の位置に表示させます。
101-102行で micro SD カードに保存されたルート証明書を取得します。
104行で SSL の Webページに記事をGET しに行きます。
ホストサーバー URL や、ターゲット URL を変えれば、自分の欲しい記事を取得できると思います。
107行で、UTF-8 文字列を Shift_JIS コードに変換しています。
それを、マルチタスクの 82行目に代入しています。
●114-127行:
ここでは、Yahoo! Japan RSS サイトの天気予報から文字列を取得しています。
120行目のホスト URL や、ターゲットURL を変えれば、自分の好きな地域の天気予報を取得できます。
ここでは、東京の天気予報になります。
天気予報の地域選択は以下のサイトから選んで、ターゲット URL を書き換えてください。
https://weather.yahoo.co.jp/weather/rss/
コンパイル書き込み実行
では、コンパイル書き込み実行させてみてください。
最初に紹介した動画のように、有機EL ( OLED )ディスプレイの表示が停止せずに、裏の CPU でWeb記事をGET できていればOKです。
シリアルモニターにはこのように表示されます。
まとめ
これで、IoT としての必須条件である、Web記事取得と、NTP時刻取得をしながら、別のCPUで動作を止めずに動かすことができるようになりました。
これは、電子工作としては革命的ですよね。
それにしても、今回の GitHub の Arduino core for ESP32 大幅アップデートによって、ESP32 ( ESP-WROOM-32 )の WiFi動作の不安がかなり解消されたことが、大いに助けになりました。
GitHub の issue で投げかけていた質問を読んでくれたのかどうか分かりませんが、開発チームの @me-no-dev さんや、@copercini さんには感謝したいです。
ありがとうございました。
m(_ _)m
今回はここまでです。
ではまた・・・。
Amazon.co.jp 当ブログのおすすめ
コメント
記事参考してArduino core for ESP32 と自作ライブラリをアップデートしての(8月4日)マルチタスク ( デュアルコア )動作確認しました。
ESP32を aitendo ESP-WROOM-32基板での単体使用、動作良好に動作してます。
マルチタスクで無いスケッチもアップデート後は問題なく動作してます。
動作時の電流値ですが、マルチタスクで約245mA、以前のスケッチで
約220mAほどです、電光掲示板的にはどちらも申し分有りませんね。
デュアルコアでの動作が電流値に出てるのかな、参考になる情報いつも
拝見してます今後とも宜しくお願いします。
太田さん
いつも当ブログをご覧いただき、そして実践してただき、感謝感謝です。
m(_ _)m
良好に動いていて安心しました。
そうですか・・・、マルチタスクで25mA 程アップですか・・・。
私はまだ計測していないのですが、思っていたよりそれほど消費していませんね。
これがDeep Sleep で動いてくれればうれしいですね。
今後の課題です。
また、何かありましたらコメント頂けると助かります。
ありがとうございました。
m(_ _)m
こんにちは!
突然ですが、プログラムをesp32に問題なく書き込み、シリアルモニタも問題なく動いていたのですが、lcd表示で、砂嵐のような画面で全く動きません。何が問題なのか教えてください。
YUKI さん
ブログご覧いただきありがとうございます。
いろいろ取り込み中の作業があり、まだ検証できていないのですが、もしかしたら GPIO の番号設定と配線が違っている可能性があります。
私もその症状に何度も出くわし、プログラム中の GPIO 番号と配線が違っていたことが何度もあり、砂嵐になってしまいました。
手が空いたら検証してみたいと思いますので、しばらくお待ちください。
YUKI さん
久々にこのプログラムを動かしてみましたが、私の環境では問題無く表示されました。
Arduino IDE は 1.8.5
Arduino core for the ESP32 は
Commits on Mar 5, 2018
を使用しています。
砂嵐になるのは、GPIO 配線違いの他に、フォントデータが読み込めていないことが考えられます。
Arduinoスケッチのフォントファイルは、microSDカード内の /font というフォルダ内で指定しています。
もしかしたら、microSD内のフォントデータが別のフォルダにあったりしないでしょうか?
その他、ESP32開発ボードのUSBケーブルが粗悪なもので電圧降下が起きて、microSDカードに供給する電圧および電流が足りていないことも考えられます。
シリアルモニターでフォントデータ読み込み不良のようなメッセージは出ていませんか?
Arduino IDE の「ツール」メニューの「Core Debug Level」のところを、「Verbose」にして、再コンパイルしてみてください。
シリアルモニターに「failed」のようなメッセージが出ていませんでしょうか?
因みに、当方の最新版自作ライブラリのバージョンは以下です。
●ESP32_SD_ShinonomeFNT beta ver 1.21
●ESP32_SD_SSD1331_Gadgets beta ver 1.1
●ESP32_SD_UTF8toSJIS beta ver 1.21
●ESP32_SSD1331 beta ver 1.71
●ESP32_WebGet beta ver 1.12
返信遅れてすいません。
その後、頑張って原因を探ってみたところ、ライブラリがちゃんとsdカードに入っていませんでした。返信していただきありがとうございます。
そういうことだったんですね。
とりあえず、原因が分かって安心しました。
こんにちは!
プログラムを参考にさせていただきましたが、コンパイル書き込みをしようとすると、「ボードESP32 Dev Moduluに対するコンパイル時にエラーが発生しました」と表示されます。
対処法をご教授いただければ幸いです。
佐藤さん
記事をご覧いただきありがとうございます。
まずお聞きしたいのは、ESP32開発ボードは何を使っていますか?
それを教えてください。
また、USBハブは使わずに ESP32開発ボードとPCを直に接続されていますか?
USBケーブルは太く短く良質のものを使用されていますでしょうか?
それと、Arduino core for the ESP32 のバージョンは何をお使いですか?
はじめまして。
Arm+mbedでお天気ガジェット作成に挑戦して挫折していたところ、こちらにたどり着きました。
余っていたトランジスタ技術のIoT Express MkIIがあったので試すと、そのまま問題なく動作しました。
素晴らしいです!
Twitterもあわせて、これからいろいろ参考にさせていただきます。
どうぞよろしくお願いいたします。
mildturkey8さん
記事をご覧いただき、ありがとうございます。
この記事は約3年半前のもので、それでもIoT Express MkIIで動いたというのは驚きです。
そういえば、そんな基板ありましたね。
お試しいただき、ありがとうございました。
でも、今、コードを見返すと、コーディング規約とか効率化とか、当時は知らない事ばかりだったので、とても恥ずかしい限りです。
正直言って、私のコードは独学なので、あまり参考にしない方が良いと思います。
ESP32やM5Stackについては、LovyanGFXライブラリというすばらしいライブラリがあるので、そちらを使った方が断然に高速で安定しています。
LCD表示はそちらを使った方がお勧めですよ~!
(^^)
mgo-tecさま
ライブラリの情報ありがとうございます!
勉強して使いこなせるようになりたいと思います。
ここのテーマとは異なりますが、Spresensとクラウドを使ったセミナーに参加したものの、ほとんど理解できていないので、ディープラーニングの記事も拝見させていただこうと思っています。
よろしくお願いたします。
Spresensは使ったことないですが、WiFiが無いので、クラウドと繋げるとなると難しそうですね。
こちらこそ今後ともこのブログをよろしくお願いいたしまーす!