2021年8月25日水曜日

Lichee Pi Zeroで無線LANを使いたい ESP8266 その1

Lichee Pi向け?の無線LANモジュールはあるみたいだけど、TELEC取得していないので
普通に使うことはできない。
そこで、気にはなっていたけど使ったことがなかったESPを最近使い始めたので、調子に乗ってLicheePIと接続してみたいと思う。
ESP8266(ESP-WROOM-02D (2MB))

UART1を有効にする

コミニュティの手順書を参考にUART1を有効にする
http://zero.lichee.pro/驱动/UART.html

ブロック図では
http://zero.lichee.pro/入门/board_intro.html#id5

IO-E21、IO-E22の割り当てをUART1に変更できる


dts、dtsiファイルの変更

手順書では、sun8i-v8s.dtsiやsun8i-v3s-licheepi-zero.dtsを書き換える手順になっているが、変更箇所を分離して自分の管理下に置きたかったので、別ファイルに記載することにした。

buildrootの外部ツリーに
board/dts/sun8i-v3s-licheepi-zero-dock-with-lcd.dts
を作成


#include "sun8i-v3s-licheepi-zero-dock.dts"

/ {
	backlight: backlight {
		compatible = "pwm-backlight";
		pwms = <&pwm 0 1000000 0>;
		brightness-levels = <0 30 40 50 60 70 100>;
		default-brightness-level = <6>;
	};

	soc {
		pio: pinctrl@01c20800 {
			uart1_pins_a: uart1@0 {
				pins = "PE21", "PE22";
				function = "uart1";
				bias-pull-up;
			};
		};
	};
};

&pwm {
	pinctrl-names = "default";
	pinctrl-0 = <&pwm0_pins>;
	status = "okay";
};

&uart1 {
	pinctrl-0 = <&uart1_pins_a>;
	pinctrl-names = "default";
	status = "okay";
};

これを読むようにconfigファイルを変更(menu menuconfig)する

BR2_LINUX_KERNEL_CUSTOM_DTS_PATH="$(BR2_EXTERNAL_LICHEEPI_ZERO_DOCK_EX_PATH)/board/dts/sun8i-v3s-licheepi-zero-dock-with-lcd.dts"

dtsとdtbの相互変換

device-tree-compiler が必要

dtsからdtb

#!/bin/bash

LINUX_KERNEL_SRC=output/build/linux-zero-4.14.y
DTS_SRC_FILE=$1
DTB_OUT_FILE=${DTS_SRC_FILE%.*}.dtb

gcc -E -P -x assembler-with-cpp -I $LINUX_KERNEL_SRC/arch/arm/boot/dts -I $LINUX_KERNEL_SRC/include $DTS_SRC_FILE | dtc -I dts -O dtb -i $LINUX_KERNEL_SRC/arch/arm/boot/dts -o $DTB_OUT_FILE

dtbからdts

作成されたdtbが意図したものになっているかを確認する

dtc -I dtb -O dts -o result.dts sun8i-v3s-licheepi-zero-dock-with-lcd.dtb

動作確認

適当なシリアルターミナルをインストールして確認する
今回はminiconにしてみた
uart1をループさせて、入力したものが返ってくるかを確認する

Lichee PiからESP8266のファーム書き込み

ファーム書き換えの毎にPCに接続するのも大変なので、LicheePiから書き込めるようにする

これには、esptool.pyを使用するとできるようだ
流れとしてはVScodeやArduino IDEでコンパイル→生成したバイナリをLicheePIに転送→LicheePiからESP8266を書き換える といった流れ

まずは、Arduinoは作成したファーム(バイナリ)が残らない?ので、残す方法
以下を参考にやってみる
https://www.jh4vaj.com/archives/8548

Arduino IDEの場合

スケッチ→コンパイルしたバイナリを出力



ワークスペースに[〜〜.ino.generic.bin]というファイル名でバイナリが作成される

VScodeの場合

/home/adeno/.arduino15/preferences.txt

build.path=/home/adeno/develop/Arduino/

を追加すると
コンパイル時にここにバイナリを保存しておいてくれる
このときのファイル名は[〜〜.ino.bin]というファイル名でバイナリが生成させる

方法によって、ファイル名が異なるので注意が必要。。

書き込み

esptool.py --port /dev/ttyS1 write_flash 0x0 sketch_mar29a.ino.bin

こんな感じでどーんっ
これで、ようやく環境が出来た、、まだ先は長い



2021年8月18日水曜日

ESP-WROOM-02D(ESP8266)を使ってみる2

本当は、今年の3月くらいにやっていたのだけど、なぜかブログにアップするのを忘れていた。
なんだかなー案件Orz



official AT firmwareでATコマンドを駆使した簡単なhttpリクエストは成功したので
少し調子に乗って、Arduino core for ESP8266 WiFi chipを使って同じようなことをしてみたい。
初めてArduino使うわ。
なので、Arduino環境の構築から。

Arduino環境構築

この手順に従ってやっていく
https://github.com/esp8266/Arduino#installing-with-boards-manager

参考
https://www.indoorcorgielec.com/resources/arduinoide設定/esp-wroom-02搭載製品
https://keijirotanabe.github.io/blog/2017/02/07/esp8266-Arduino-170207/

Arduino IDE

https://www.arduino.cc/en/software

今回は、ディストリビューションのソフトウェア管理からインストールしちゃう。
apt install

後のVScode連携でハマった(IDEの場所をVSCodeから見つけられない)ので、
公式からインストールすることにした。
https://www.arduino.cc/en/Guide/Linux

ボードマネージャーに追加

https://arduino.esp8266.com/stable/package_esp8266com_index.json

HelloWorld

巷のサンプルのままだけど。

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

void loop() {
  // put your main code here, to run repeatedly:
  Serial.println("Hello World");
  delay(1000);
}


これがArduinoかー。わずか3行でこんなことができちゃうんだ。すごい世界観だ。

VSCode

なにやら、VSCodeの拡張機能があるみたい。すてき。
https://github.com/Microsoft/vscode-arduino
https://qiita.com/narikei/items/847613a8f01a9e1527d7#arduinoに書き込む
https://qiita.com/kamata1729/items/10226444bc89e2533e4f

上記を参考に導入。


Arduinoでhttpリクエストしてみる

Arduinoはサンプルコードがいっぱいある。
参考にテストコードを作成

#include <ESP8266WiFi.h>
#include <time.h>

WiFiClient client;

void setup() {
  // put your setup code here, to run once:
  Serial.begin(115200);
  WiFi.mode(WIFI_STA);
  WiFi.disconnect();
  testRun();
}

void printScanResult(int networksFound)
{
  Serial.printf("%d network(s) found\r\n", networksFound);
  for (int i = 0; i < networksFound; i++)
  {
    Serial.printf("%d: %s, Ch:%d (%ddBm) %s %s\r\n", 
      i + 1, WiFi.SSID(i).c_str(), WiFi.channel(i), WiFi.RSSI(i), 
      WiFi.encryptionType(i) == ENC_TYPE_NONE ? "open" : "",WiFi.BSSIDstr(i).c_str());
  }
  Serial.printf("End\r\n");
}

void show_WifiStatus(){
  char result[32];
  switch(WiFi.status()){
    case WL_CONNECTED:
      strcpy(result,"connection is established.");
      break;
    case WL_NO_SSID_AVAIL:
      strcpy(result,"SSID cannot be reached.");
      break;
    case WL_CONNECT_FAILED:
      strcpy(result,"connect failed.");
      break;
    case WL_IDLE_STATUS:
      strcpy(result,"idle.");
      break;
    case WL_DISCONNECTED:
      strcpy(result,"disconnect.");
      break;
    default:
      strcpy(result,"unknown.");
      break;
  }
  Serial.printf("Connection status: %s\r\n",result);
}

void testRun(){
  Serial.printf("Scan AP\r\n");
  delay(100);
  WiFi.scanNetworksAsync(printScanResult);
  
  delay(10000);
  const char ssid[] = "************";
  Serial.printf("Connect AP\r\n");
  show_WifiStatus();
  Serial.printf("Connecting to %s\n", ssid);
  WiFi.begin(ssid, "************");
  show_WifiStatus();
  while (WiFi.status() != WL_CONNECTED)
  {
    delay(500);
    Serial.print(".");
  }
  Serial.println();
  show_WifiStatus();
  Serial.print("Connected, IP address: ");
  Serial.println(WiFi.localIP());
  configTzTime("JST-9", "pool.ntp.org", "jp.pool.ntp.org"); 

  delay(10000);

  time_t t;
  struct tm *tm;
  static const char *wd[7] = {"Sun","Mon","Tue","Wed","Thr","Fri","Sat"};

  t = time(NULL);
  tm = localtime(&t);
  Serial.printf("ESP8266 :  %04d/%02d/%02d(%s) %02d:%02d:%02d\r\n",
        tm->tm_year+1900, tm->tm_mon+1, tm->tm_mday,
        wd[tm->tm_wday],
        tm->tm_hour, tm->tm_min, tm->tm_sec);

  delay(3000);
  Serial.println("\r\nStarting connection...");
  if (client.connect("httpbin.org", 80)) {
    Serial.println("connected");
    // Make a HTTP request:
    client.println("GET /ip HTTP/1.0");
    client.println();

    delay(3000);
    while(client.available()) {
      String line = client.readStringUntil('\r');
      Serial.print(line);
    }

    client.stop();
  }

  WiFi.disconnect();
  delay(3000);
  show_WifiStatus();
}

void loop() {
  delay(500);
}

なんとなく、わかったような。。
久しぶりにCだなぁ。

2021年8月17日火曜日

ESP-WROOM-02D(ESP8266)を使ってみる1

安価に無線LANモジュールを入手出来ないかと模索中。 Lichee Pi Zeroにつなげたいじゃん。
ESP-WROOM-02D https://akizukidenshi.com/catalog/g/gM-13289/とか安いじゃん @360
開発ボード https://www.digikey.jp/product-detail/ja/espressif-systems/ESP8266-DEVKITC-02D-F/1965-1001-ND/9649768

技適も問題なし。


本当は、今年の3月くらいにやっていたのだけど、なぜかブログにアップするのを忘れていた。
なんだかなー。

準備

用意したもの

※フラッシュメモリの容量は2MB

ドキュメント

書き込みツール

  • windowsはESPFlashDownloadTool
  • pythonツールもある[rsptool.py]

SDKなど

技適のメモ

カスタムファームでの技適問題はスイッチサイエンスさんが確認してくれている
https://mag.switch-science.com/2016/01/20/esp-wroom-02_telec/

なので、

ファーム 技適
The official AT firmware (ESP8266_NONOS_SDK) OK
RTOS (ESP8266_RTOS_SDK) OK
Arduino core for ESP8266 WiFi chip OK
MicroPython ?
FreeRTOS https://github.com/aws/amazon-freertos ?

初期ファームで起動・最新バージョンに書き換え

ready
AT+GMR
AT+GMR
AT version:1.6.2.0(Apr 13 2018 11:10:59)
SDK version:2.2.1(6ab97e9)
compile time:Jun  7 2018 19:34:26
Bin version(Wroom 02):1.6.2
OK

Quick Start Guideの手順書通りにファーム書き換え、windowsが必要になったけどね。。
rsptool.py使えば、linuxでもできる気がするけど試していない。

ready
AT+GMR
AT+GMR
AT version:1.7.4.0(May 11 2020 19:13:04)
SDK version:3.0.4(9532ceb)
compile time:May 27 2020 10:12:22
Bin version(Wroom 02):1.7.4
OK

The official AT firmwareでhttpリクエストしてみる

ATコマンドを駆使してhttpリクエストをやってみる
ATコマンドは
https://www.espressif.com/sites/default/files/documentation/4a-esp8266_at_instruction_set_en.pdf
https://www.espressif.com/sites/default/files/documentation/4b-esp8266_at_command_examples_en.pdf
を参考にした

今勉強中のPythonでやってみる
pyserialを使うので

pip3 install pyserial

が必要。

テスト用プログラム

import serial
import threading
import time
import io

busy_flg = False
rcv_flg = True

def _rcv() :
    global busy_flg
    global rcv_flg
    global sio
    while rcv_flg:
        rawline = sio.readline()
        line = rawline.replace("\r","").replace("\n","")
        if (line == "OK") or (line == "SEND OK") :
#            print("Found \"OK\".")
            busy_flg = False
        elif (line == "FAIL") or (line == "ERROR") :
#            print("Found \"FAIL\" or \"ERROR\".")
            busy_flg = False

        if len(line) > 0 :
            print(line)

def _send(data,nocr=False) :
    global busy_flg
    global sio
    while busy_flg == True :
        time.sleep(1)
        print("*")
    busy_flg = True

    print("snd>"+data)
    if nocr:
        sio.write(data)
    else :
        sio.write(data+"\r\n")
    sio.flush()


ser = serial.Serial('/dev/ttyUSB1',115200,timeout=0.5)
sio = io.TextIOWrapper(io.BufferedRWPair(ser, ser))

rcv_thread = threading.Thread(target=_rcv)
rcv_thread.daemon = True
rcv_thread.start()

try:
    _send(data = "AT+GMR")

    _send(data = "AT+CWMODE=1")     # Station mode 
    _send(data = "AT+CWLAP")        # Lists Available APs
    _send(data = "AT+CWJAP_CUR=\"[ESSID]\",\"[password]\"")        # Connects to an AP

    _send(data = "AT+CIFSR")        # Gets the local IP address 
    _send(data = "AT+CIPSTA?")  

    _send(data = "AT+CIPSNTPCFG=1,9,\"pool.ntp.org\",\"jp.pool.ntp.org\"") # Sets the Configuration of SNTP 
    _send(data = "AT+CIPSNTPTIME?") # Checks the SNTP Time

    _send(data = "AT+CIPSTART=\"TCP\",\"203.137.163.123\",80")        #protocol,server IP and port
    
    http_body="GET / HTTP/1.0\r\n"
    http_body+="\r\n\r\n"
    http_body_length = len(http_body)

    _send(data = "AT+CIPSEND="+str(http_body_length))
    _send(data = http_body,nocr=True)
    time.sleep(10)

    _send(data = "AT+CIPCLOSE")
    _send(data = "AT+CWQAP")        # Disconnects from the AP 

except KeyboardInterrupt:
    print("Bye.")
    

print("Exit.")
busy_flg = False
rcv_flg = False
rcv_thread.join()
ser.close()

やってること

ATコマンドを順に実行している。エラー処理などは未実装。

  1. バージョン表示
  2. ステーションモード(STA)に変更
  3. アクセスポイント(AP)を検索
  4. APに接続
  5. APからもらったIPアドレスなどを表示
  6. NTPサーバーを設定(“pool.ntp.org”,“jp.pool.ntp.org”)
  7. NTPサーバーから時刻を取得
  8. WEBサーバーに接続(今回は、自分のグローバルIPアドレスを確認できるサービス http://ipaddr.show/ のIPを設定[203.137.163.123])
  9. WEBサーバーにリクエスト送信
  10. 10秒待つ
  11. TCPセッション切断
  12. APから切断

実行結果

adeno@drakorange:~/develop/ESP8266$ python3 test.py 
snd>AT+GMR
AT+GMR
AT version:1.7.4.0(May 11 2020 19:13:04)
SDK version:3.0.4(9532ceb)
compile time:May 27 2020 10:12:22
Bin version(Wroom 02):1.7.4
OK
*
snd>AT+CWMODE=1
AT+CWMODE=1
OK
*
snd>AT+CWLAP
AT+CWLAP
*
*
+CWLAP:(4,"****************",-79,"**:**:**:**:**:**",1,5,0,4,4,7,1)
(省略)
OK
*
snd>AT+CWJAP_CUR="SSID","PASSWORD"
AT+CWJAP_CUR="SSID","PASSWORD"
*
*
*
WIFI CONNECTED
*
*
WIFI GOT IP
OK
*
snd>AT+CIFSR
AT+CIFSR
+CIFSR:STAIP,"192.168.1.19"
+CIFSR:STAMAC,"**:**:**:**:**:**"
OK
*
snd>AT+CIPSTA?
AT+CIPSTA?
+CIPSTA:ip:"192.168.1.19"
+CIPSTA:gateway:"192.168.1.1"
+CIPSTA:netmask:"255.255.255.0"
OK
*
snd>AT+CIPSNTPCFG=1,9,"pool.ntp.org","jp.pool.ntp.org"
AT+CIPSNTPCFG=1,9,"pool.ntp.org","jp.pool.ntp.org"
OK
*
snd>AT+CIPSNTPTIME?
AT+CIPSNTPTIME?
+CIPSNTPTIME:Wed Mar 31 06:19:39 2021
OK
*
snd>AT+CIPSTART="TCP","203.137.163.123",80
AT+CIPSTART="TCP","203.137.163.123",80
CONNECT
OK
*
snd>AT+CIPSEND=20
AT+CIPSEND=20
OK
*
snd>GET / HTTP/1.0



> 
Recv 20 bytes
SEND OK
+IPD,133:HTTP/1.0 200 OK
Date: Tue, 30 Mar 2021 21:19:43 GMT
Content-Length: 16
Content-Type: text/plain; charset=utf-8
***.***.***.***
CLOSED
snd>AT+CIPCLOSE
AT+CIPCLOSE
ERROR
*
snd>AT+CWQAP
Exit.
AT+CWQAP

いい感じ
なんとなく、わかってきた。

2021年8月2日月曜日

GEOのノイキャン付きワイヤレスイヤホンを使ってみる


最近、ストレスのはけ口が物欲に向かっている気がする。イケない傾向だ。。
ツイッターかなんかで、安くて性能もそこそこと評判だったものを、気づいたら手もとにあった。

GRFD-SWE500HT01


ちょっとだけ集中したいときに、ノイキャンあると嬉しいし
マスク外出が増えてきたので、ケーブル付きだとマスクと絡まってうっとおしい。

スペックは
https://geo-online.co.jp/campaign/special/other/geoselection/earphones/swe500ht01.html

プレスリリースには、QCYのGEO専売パッケージって書いてあった。
https://www.geonet.co.jp/news/news2020/20820/



ネットの記事を見ると、CQYのアプリがそのまま使える的なことが書いてあった。
https://watchmono.com/e/geo-swe-ht01-bg-review-check

ほえー割り切っているね。
こういうビジネスが今後どうなるか興味ある。
裾野が広がるんじゃなかと思う。

良い点

  • 件のCQYアプリで、左右のタッチ機能の割当を変更できる
  • 超シンプルなデザイン 主張がないのがとても良い
  • 耳から外すと音楽一時停止する
  • 音楽の音量が小さくても聞こえる気がする(これがノイキャンの効果?)

悪い点

  • レビュー通り高音がサラサラ?している
    プレーヤーの方で調整している人がいた。
  • アプリの通知がうっとおしい
  • アプリの個人情報登録がちょっと抵抗がある
    よくわからないが、個人登録しない状態でも使えている
  • たまーに「ブツッ」という20分に1回くらい。
    出先だと起きない気がするからwifiとの干渉かしら?
  • 結構早めに耳が痛くなる まぁ休憩の目安ということでいいんだけど。

よくわからない点

  • ペアリングは無条件に受け入れ?
    スマホでペアリングしていて、ChromeBookでペアリングできた。これって横取りできるってことけ? ちがった。 スマホと接続になっていないときの話だった。

  • ChromeBookとペアリングして音楽聴きながら、スマホのQCYアプリでノイキャンの切り替えができた
    そういうもんなのか??便利だからいいんだけど。

  • ノイキャンの効果は
    体感できたのは、「アウトドアモード」で風斬り音が弱まった
    ANCで音よりも振動に意識が向くようになった。
    もちろん音も聞こえるんだけど。
    高級なiPodsとかWH-1000XM4だとどんな感じになるんだろうか。気になる。
    これは、沼だ。あぶないあぶない。

  • ハンズフリーは
    まだ試していない。ワイヤレスだと、完全に独り言みたいになるので、ちょっと勇気が出ない。

その他

取説はここに電子がある
https://product.geo-online.co.jp/wp-content/uploads/GRFD-SWE500HT01_manual.pdf

これでしばらくは物欲の虫がおとなしくしてくれるといいのだが。
にしても、マスクのつけ外しやちょっとした動きのときにケーブルを気しないってこんなに快適なんだとびっくりした。