macsbug

Just another WordPress.com site

Archive for 11月 2016

CH340 kernel crash memorandum

with 2 comments

USB to serial chip CH340 は マックで カーネルクラッシュ を起こす。      2016.11.30

最新では CH340ドライバー 「CH34x_Install_V1.3.pkg」をインストールし
動作しているのが正常です。しかし私の場合 それでは認識しませんでした。
つまり ver 1.1「ch34xInstall.pkg」や ver 1.3「CH34x_Install_V1.3.pkg」を
インストールできないという不可解な現象。
私だけの現象かも知れませんが その解決方法を備忘録としました。

解決方法:古い  CH340ドライバー (2012.10.15) (左) を インストール後に
_    新しい CH340ドライバー (2013.12.25) (右) を インストールする。


 

使用環境:
iMac 27 Mid 2010 OS X 10.8.5 Mountain Lion。 Arduino IDE 1.6.13。


 

経緯:「とりあえず対策」で過ごす。
USB to serial chip CH340 を使用したモジュールは マックでカーネルクラッシュ
を起こす。原因不明の中で対策としてCH340を接続してからマックの電源を起動
すると CH340 を認識し使用するという恥ずかしい状態。
ところが 最近になり これも効かずカーネルクラッシュの嵐が発生しました。

過去にこの経緯から「CH340G USB Serial Module in OSX」を記載しましたが
解決はしていませんでした。

原因と思われる「usb.kext」をターミナルで削除するとカーネルクラッシュは
無くなりましたが 以下の2つのバージョンをインストールしても
「全く認識しない」という 悲惨な状態になりました。
_  CH341SER_MAC 2013年12月25日 「ch34xInstall.pkg」
_  CH341SER_MAC 2016年8月16日  「CH34x_Install_V1.3.pkg」


 

原因:
1. カーネルクラッシュの原因は usb.kext である。
_  場所は System/Library/Extensions/usb.kext にある。


 

対策:以下の3つ( usb.kext 削除, OLD Driver, New Driver Install ) を実施します。
1. usb.kext を削除する。
_  usb.kext を直接ゴミ箱へ捨てるか ターミナルを使用しコマンドを実行します。
_  sudo rm -rf /System/Library/Extensions/usb.kext
_  これにより System/Library/Extensions/ の中の usb.kext は無くなります。
_  マックを再起動します。

2. 古いドライバー「USB CH341/CH340 MAC OS32, MAC OS64」を入手する。
_  Модуль: CH340G にある USB CH341/CH340 MAC OS32, MAC OS64 を DL する。
_  確認:DLファイルの中にある ch34xInstall.pkg の日付は 2012.10.15 である。
_  ch34xInstall.pkg でインストールする。
_  System/Library/Extensions/ に usb.kext ができ ver は 1.1 です。
_   
_   
_  マックを再起動します。
_  Arduino IDE のシリアルポートは 「/dev/cu.wch ch341 USB=>RS232 fd1420」となる。
_ 
_  ただし この状態では Arduine IDE は コンパイルエラーがでます。

3. 新しいドライバー「CH341SER_MAC.ZIP」を入手する。
_  How To Use Cheap Chinese,,,Ch340G Serial/USB chip にある
_  CH341SER_MAC.ZIP を DL する。
_  確認:DLファイルの中にある ch34xInstall.pkg の日付は 2013.12.25 である。
_  ch34xInstall.pkg でインストールする。
_  System/Library/Extensions/ に usb.kext があり ver は 1.1.1 です。
_   
_   
_  マックを再起動します。
_  Arduino IDE のシリアルポートは 「/dev/cu.wchusbserialfd1420」となる。
_ 
結論:
_  マックの電源オン状態で CH340 を接続してもカーネルクラッシュは起きず
_  コンパイルも正常に行われる様になりました。


 

システムレポート:システムレポートによる USBの状態 は以下です。
_ 左:CH340:確かに名前の無いチープなUSBです。 右:CP2102。


CH340 を認識しない場合のハード的回避方法:CP2102 を介して読み書きする。

1. ESP-01 に書き込む方法:
_  nodeMCU Board の CP2102 を使用する。(nodeMCUは ebayで380円です)
_  NodeMCU のEN端子(青矢印)を GND に接続し nodeMCUを停止する。
_  Arduino IDE: “Generic ESP8266 Module” を選択し
_        Reset Method : “nodemcu” にする。

 nodeMCU  ESP-01  OLED
 EN = GND  –  –
 RX  RX  –
 TX  TX  –
 RST  RST  –
 D3(0)  GOPI 0  –
 3V3  CH_PD  SDA
 –  GPIO 2  SCL
 GND  GND  GND
 3V3  VCC  VCC


 

2. WeMos D1 mini に書き込む方法:
_  nodeMCU Board の CP2102 を使用する。
_  NodeMCU のEN端子(青矢印)を GND に接続し nodeMCUを停止する。
_  D1 mni CH340 の Pin 8 – 9 を Jumper ( Short ) し CH340 を停止する。
_   ( D1 mini X1:CH340 の X’tal を停止する為です)
_  Arduino IDE ツールの設定:”WeMos D1 R1 R2 & mini” を選択する。

 nodeMCU  D1 mini  OLED
 EN = GND  –  –
 –  CH340
pin 8 – 9 Short
 –
 RX  RX  –
 TX  TX  –
 RST  RST  –
 D3(0)  D3(GPIO 0)  SDA
 –  D2(GPIO 2)  SCL
 GND  GND  GND
 3V3  VCC  VCC

 

感想:CH340 は チープで 何かと疲れるチップです。
カーネルクラッシュの経緯:OSはSnowleopard の時は問題なく「/dev/cu.wchusbserialfd1420」
_ で使用できていました。OSをMountain Lion後に 徐々にカーネルクラッシュが起き始める。
.
認証:最近 safariブラウザーで幾つかのサイトにアクセスできなくなりました。
_ 代表的なものは Processing のサイトでこれが繋がらない為 極めて不便。(Sierra OSはOK)
_ たぶん Safari ブラウザーは セキュリティー機能強化の為だと思っています。
_ とりあえずは Google Chrome でしのいでいます。たぶん機能が甘いからかも知れません。
_ この問題は どうやらセキュリティーアップデートの件でアップルでの認証期限が切れた
_ 件の現象だと思っています。他にも時折「認証」文字がでてくる事が多くなりました。
_ これらは OSのバージョン と ブラウザー の組み合わせによるものと思われます。
.
CH340 搭載モジュール:カーネルクラッシュの場合 WeMos D1 mini や CH340 タイプの
_ nodeMCU は使用できなくなります。特に今まで作成した物が変更できなくなる事態。
_ OTA書き込み方法もあると思いますが USB接続が必要となる場面も多々あります。
_ この中国産の怪しいチップは本当にチープに感じます。安いですが手間がかかり
_ 困ります。それで最近は少し高くても CP2102製品 を購入しています。
_ ま〜 何はともあれ 解決してホットしました。
.
CH340 ドライバー:3つのバージョンがある。
_  v 1.1     :CH341SER_MAC  2012年10月15日 「ch34xInstall.pkg」
_  v 1.1.1  :CH341SER_MAC  2013年12月25日 「ch34xInstall.pkg」
_  v 1.3    :CH341SER_MAC  2016年  8月16日  「CH34x_Install_V1.3.pkg」
_  新しいバージョンとして「CH34x_Install_V1.3.pkg」があるが これを実行しても
_  CH340 を認識しませんでした。
_  OS X Yosemite や EI Captain での対応も必要らしい。
.
_  友人の情報では「CH34x_Install_V1.3.pkg」で問題なく動いているとの事。
_  私の場合 v 1.1 は インストールできるが v 1.1.1 はその後にタマにインストールできる。
_  そして v 1.3 は どうやってもインストールできない状態。
_  インストーラーが何故インストールできないのかは不明。
.
USBシリアル変換モジュール:秋葉で1000円位する物があり 結構高い製品だと感じました。
_ CP2102 の NodeMCU なら 300円台で買えますからね。
.
ネット情報:多くの記事がありますが 私の様な状況を一気に解決する記事は見受けられ
_ ませんでした。それは 恐らく一部の条件を前提に解決していたと思われます。
.
疑問:CH340 のドライバーは何処に入ったのでしょうか? usb.kext とも思われます。
_  usb.kext を削除しても CP2102 は動作しています。そうなるとCP2102 ドライバー
_  は どういう名前で何処に入っているのでしょうか?
_  他、過去に使用した USB の名前が残っており 消したいのですが 方法が解りません。
_

 

Written by macsbug

11月 30, 2016 at 2:22 am

カテゴリー: Arduino, ESP8266

Communicate ESP8266 and iPad directly with UDP

leave a comment »

ESP8266 と iPad を UDP で 直接通信する方法。              2016.11.20

直接通信は インターネット無しで 接続が可能です。特に外出時に便利です。
相手側は ESP8266 や PC でも直接通信が可能になります。
既に ネット上で解説記事がありますが 備忘録として まとめました。

便利な直接通信:
以前の記事「Display the graph on the iPad」でセンサーの値を ネットワーク
経由 ( 家庭内LAN経由 ) iPadで受信し 表示する方法がありました。
しかし 目の前にある装置に ネット経由で接続する必要は無い事と 外では
無線環境が無い事や ネット経由で簡単に通信が出来ない 場合があります。
.
そこで ESP8266 と iPad を 直接通信する事により ネット環境が無くとも
接続が可能になります。さらに 通信費用もかかりません。
ESP8266 (192.168.4.1:9000) → iMac(192.168.4.2:9000) : IP,PORT
ESP8266 (192.168.4.1:7000) ← iMac(192.168.4.2:7000) : IP,PORT

フィードバックの必要性:
装置間の通信は 相手が指示通りの状態になったか 確認が必要です。
送信後に 相手の結果 を受信する必要があり 通信が回転します。



 

ESP8266 の設定: WiFiUDP を使用し PORT を設定する。

// ESP8266
#include <ESP8266WiFi.h>                 // WiFi
#include <WiFiUDP.h>                     // UDP
const char *ssid = "wifi";               // SSID
const char *pass = "";                   // PASSWORD
static WiFiUDP udp;                      // UDP Object
#define ESP_RX_PORT 7000                 // ESP Receiver port
#define ESP_TX_PORT 9000                 // ESP Transmit Port
IPAddress ESP_IP;                        // ESP IP 192.168.4.1
IPAddress EXT_IP;                        // ext IP 192.168.4.2
char buff[32];                           // receive buffer

void setup(){
 WiFi.mode(WIFI_AP);                     // AP Mode:direct connection
 WiFi.softAP(ssid, pass);                // ESP8266:SSID, password
 ESP_IP = WiFi.softAPIP();               // 192.168.4.1 localIP
 udp.begin(ESP_RX_PORT);                 // ESP:UDP Rx port=7000


 

iPad の設定: socket を使用し IP と PORT を設定する。

// iPad
import socket
HOST, PORT = '192.168.4.1', 7000          # ESP8266 ip,port
rx = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
rx.bind(('192.168.4.2', 9000))            # ipad tx port
tx = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)


 

ESP8266 から 送信する。

// ESP8266 transmitt
String data = "t/0/0/0";                  // 送信データ
udp.beginPacket(EXT_IP, ESP_TX_PORT);     // Packet transmit
udp.print(data);                          // data   transmit
udp.endPacket();                          // end of transmit

iPad で 受信する。

// iPad receiver
udp udp_receiver('')                     # ipad を受信状態にする
while mode != 'd':                       # 受信データの中味を確認する

udp_receiver('1')                        # 音声出力時の為の socket を遮断する

def udp_receiver(s);                     # udp 受信ルーチン
 gloval rx, d1, d2, temp, humi           # 共通変数
 if s == "1": rx.setblocking(1)          # socketの遮断をする
 d1 = str(rx.recv(32), 'utf-8')          # rx : socket を受信する
 d2 = d1.split('/')                      # '/' で区切られたデータを d2[] に一括保存する
 mode = d2[0]                            # 受信データの先頭 [0]
 if mode == "d":                         # 先頭データが "d" の場合の処理をする
  temp = round(float(d2[1]), 1)          # 受信データの分類その1
  humi = round(float(d2[2]), 1)          # 受信データの分類その2


 

iPad から 送信する。

// iPad transmitt
udp_transceiver('1')                      # ipad -> ESP8266   '1' を送信する
udp_receiver('1')                         # '1' に対する ESP8266 の返事を受信する
ret = str(mode) + str(sw)                 # 受信したデータ
while (ret) != 't1':                      # 't1' の場合の処理をする

def udp_transceiver(s);                   # udp 送信ルーチン
 global tx, HOST, PORT                    # 共通変数
 tx.sendto(bytes(s,'utf-8'),(HOST,PORT))  # データ s を送信する

ESP8266 で 受信する。

// ESP8266 receiver
int rx = udp.parsePacket();              // Packet 受信状態を調べる
 if (rx) {                               // 受信がある場合の処理をする
  int len = udp.read(buff,rx);           // 受信(buff)の長さを調べる
  if (len>0)buff[len] = '\0';            // 受信がある場合の処理をする
   ipad_RX_IP = udp.remoteIP();          // iPad IP 192.168.4.2
   buff[len] = '\0';                     // Termination charactor
   int c = buff[0];                      // header:受信データの先頭
   if ( c == '1' ){                      // header:受信データの先頭
                                         // 受信データの処理をする


 

感想:
無線環境:目の前にある装置にインターネット経由で接続する必要は
_ 無い事とネット回線の無い所でも自由に接続して使用できる訳で
_ す。
.
IP アドレス:最初は 192.168.4.2 が自動的に割り振られます。
_ もう一台追加すると 192.168.4.3 が 割り振られます。
.
フィードバックの重要性:温度測定程度ならフィードバックは必要
_ ないかも知れませんが IoTで遠隔操作や特に電力をコントロール
_ する時はかならず必要です。航空機では2重3重の回路やソフト
_ がありフィードバックも含め 安全性が確保されています。
_ この様な視点で IoT 製品がどの程度 安全な製品であるかを仕様
_ として表示していない場面が多いのを見受けます。
_ 又 その商品を説明するメディアや記事も同様です。
.
ワイヤレス:直接通信の例として 3軸アクセレーターやジャイロの装置
_ から データをWiFiでPCに送り PCの画面に表示ができる様になり
_ ワイヤレスの小型モーションセンサー等が出来ます。
_ こうした装置のワイヤレス環境はなかなか面白い感覚です。次回!
_  



Written by macsbug

11月 20, 2016 at 10:00 am

カテゴリー: ESP8266

Digital Compass HMC5883L with ESP8266

leave a comment »

ESP8266 + HMC5883L で デジタル・コンパス を作りました。           2016.11.15

HMC5883L は 3軸地磁気センサー です。費用は 927円です。


 

Processing によるマック上での表示。(スケッチ:HMC5883L_processing)


 

準備:費用=927円   : 円レートで価格が変動します。2016.11.15 現在(1$ 107.85)。

No.  Nomen  Link  Price(円)  Memo
01 WeMos D1 mini *  D1 Mini 347  1個 C 4.34
02 HMC5883L  HMC5883L 262  1個 GBP 1.94
03 1.4″ 128X120 SPI Color TFT  1.44″ Color TFT 318  1個 C 3.98
04 チップ抵抗 10KΩ  4個  –
05 カプトンテープ  –  –
05 両面テープ  –  –
06 Library:HMC5883L Arduino-HMC5883L jarzebski氏に感謝
07 設定:magnetic declination  地域の設定  –
08 校正  HMC5883L_calibrate  –

.
* WiFi.mode(WIFI_OFF);:この命令で送信電波を停止し without TELEC にします。
.
1.44″ TFT:Ver 1.1, V1.4, V2.1 があります。基板の裏に記載してあります。購入者
_ からは選択ができなく どれが来るか解りません。おおまかにはイニシャライズ
_ によって画素の位置が変わります。今回のスケッチは 宣言文で Ver A,C を選択
_ する事により対応できる様にしてあります。調べるとかなり奥が深いです。
_ 1.44″ でなく 1.8″ TFT を使用する方法が得策です。
.
HMC5883L ( GY-273 ):VCC=3.3V, SDA,SCLは 3.3V入力です。DRDYは使用しません。
_ 回路図参照の事。回路図に誤記あり:詳細は参照の*に記載。


 

配線:TFT基板は 3.3V使用の為 基板上の U1 LDO(5V to 3.3V) の J1 Jumper は
_  ジャンパーをします。(しなくても動作します)
_  チップ抵抗4個は TFT基板の上にカプトンテープを敷きハンダ付けします。
_  D1 mini は両面テープで TFT基板に直付けし 11本の配線をします。


 

地磁気センサーの設定:TFTの表示と地磁気センサーの向きを合わす必要があります。
_ 方位磁石やスマホの方位計を参照し 針とN極の方向を合わせ 基板に磁気センサー
_ を固定します。


 

地磁気センサー:
低価格と動作確認済みの中から HMC5883L(GY-273) を使用しました。
GY-85(HMC5883L) も動作確認しましたので使用できます。
3軸地磁気センサー( Magnetic ) は 以下の物があり 価格は高いですが GY-9150 や
GY-85 は Gyro, Acclerometer を含み  他の応用が可能となります。
MAG3110 は 値の幅が狭く正しい値が取れない為に 課題とします。


 

ライブラリー HMC5883L:magnetic-declination 値 と 校正値の設定。
_ HMC5883L ライブラリーは 複数ありますが 動作しない物があります。
_ 設定値:magnetic-declination.com の値を設定します。
_  Find the magnetic declination at your location に接続し magnetic-declination
_  を入手。東京の場合は  「-7’25E (negative)」 で 以下のスケッチになります。
_  float dec_angle=(-7+(25.0/60.0))/(180/M_PI); // Tokyo:-7.25
_ 校正値:ライブラリの中にあるサンプル「HMC5883L_calibrate」を実行。
_  以下のスケッチになります。
_  compass.setOffset(32, -202); // Set calibration offset
_ 感度:HMC5883L_RANGE_1_3GA を使用しています。*=同文
_  HMC5883L_RANGE_8_1GA : 8.1 Ga 4.35 mG 230 Lsb/gauses
_  *5_6GA : 5.6 Ga 3.03 mG 330,*4_7GA : 4.7 Ga 2.56 mG 390
_  *4GA : 4 Ga 2.27 mG 440,*2_5GA : 2.5 Ga 1.52 mG 660
_  *1_9GA : 1.9 Ga 1.22 mG 820,*1_3GA : 1.3 Ga 0.92 mG 1090 : default
_  HMC5883L_RANGE_0_88GA : 0.88Ga 0.73 mG 1370
_ レンジ:3つ:HMC5883L_SINGLE を使用しています。
_  HMC5883L_IDLE, HMC5883L_SINGLE,HMC5883L_CONTINOUS
_ 計測モード:HMC5883L_DATARATE_30HZ を使用しています。
_  HMC5883L_DATARATE_75HZ, *30HZ,*15HZ, *7_5HZ,*3HZ, *1_5HZ
_ サンプルアベレージ:HMC5883L_SAMPLES_8 を使用しています。
_  HMC5883L_SAMPLES_8, *4,*2,*1


 

参考:
haoyuelectronics:Index of /Attachment/GY-273:モジュール回路図
_  * この回路図はピン番号がずれています。1,2,3,4,5 は 1,5,2,3,4 です。
Axis_Compass_Magneticfield_Module-SCHEMATIC:モジュール回路図
_  SDA,SCLにPull_up 抵抗の無い回路図です。
Henny’s Bench:Arduino GY-273 HMC5883L Magnetometer Compass Tutorial
I2Cdevlib:HMC5883L Class Reference
dev/jarzebski:3-osiowy magnetometr HMC5883L
Manualzz:29133-CompassModuleHMC5883L-v1.0
HMC5883L_3-Axis_Digital_Compass_IC
simtronyx-:Digitaler Kompass: HMC5883L(GY-271),TFT(HY-1.8)
HMC5883L 製作マニュアル:秋月さんのページから。
HMC5883L 半導体資料:秋月さんのページから。
秋月:HMC5883L DIP, HMC5883L / HMC5883L モジュール・データシート
Strawberry Linux:HMC5883L


 

感想:
コンパスの凄さ:子供の頃 初めて手にした丸いコンパス を回して遊んだものです。
_ その時 目に見えない磁力で方向が解る事が不思議でした。 現在 電子コンパス
_ を個人で作れる時代になりました。
部品価格:国内での価格は相変わらず高いです。4桁には驚きます。
_ ebay:HMC5883L:262円。
_ 秋月:HMC5883L DIP KIT:600円
_ aitendo:デジタルコンパスモジュール [ATD5883L]:695円
_ Strawberry Linux:HMC5883L:700円
_ スイッチサイエンス:HMC5883L:1868円
_ 
地磁気センサーとライブラリー:価格では HMC5883L を 選択。ライブアリーは
_ Arduino-HMC5883L を選択。jarzebski氏に感謝致します。
_ 地磁気測定は要素が多く 設定や校正等も必要です。
周囲の磁力:磁力の付いた物を近づけると針が回る感度があります。
ESP8266の端子:GPIO15はスケッチ書込みの為に Low です。Hi を出力する物は
_ 接続できません。CS 信号は接続可能で書込み時のエラーも回避できます。
GY-85, GY9150:Gyro とAccelero Meter のチップが搭載されていますので これを
_ 使用した物が直ぐ作れる環境になり 3次元の位置情報や加速度を楽しめます。
Processing :ライブラリーにある Processing でのスケッチは大変助かりました。
_ 完成度の高い表示は 素晴らしいですね。再び jarzebski氏 に感謝致します。


 

スケッチ:

// Digital Compass                             // 2016.11.12 macsbug
// ESP8266 + HMC5883L + 1.44" Color TFT        //
//--------------------------------------------------------------------
// http://www.jarzebski.pl/arduino/czujniki-i-sensory/3-osiowy-magnetometr-hmc5883l.html
// https://github.com/jarzebski/Arduino-HMC5883L  Arduino-HMC5883L
// https://www.youtube.com/watch?v=zG3uzQW3wc0
// Digital Compass: HMC5883L (GY-271), 1.4" SPI TFT (HY-1.8)
// http://blog.simtronyx.de/digitaler-kompass-hmc5883l-gy-271-tft-hy-1-8-und-ein-arduino/
// http://www.ngdc.noaa.gov/geomag-web/#declination : Magnetic Field Calculators
//--------------------------------------------------------------------
// Find yours here: http://www.magnetic-declination.com/
// Tokyo:
// Latitude: 35° 41' 22.2" N
// Longitude: 139° 41' 30.1" E
// Magnetic declination: -7° 25' 
// Declination is NEGATIVE (WEST)
// Inclination: 49° 32' 
// Magnetic field strength: 46597.1 nT
//--------------------------------------------------------------------
// Set declination angle on your location and fix HDG
// You can find your declination on: http://magnetic-declination.com/
// (+) Positive or (-) for negative
// Tokyo declination angle is -7'25E (negative)
// Formula: (deg + (min / 60.0)) / (180 / M_PI);
// float dec_angle = (-7 + (25.0 / 60.0)) / (180 / M_PI);
// TFT 128x128 : x = 1 to 127, y = 0 to 127
//--------------------------------------------------------------------
#include <ESP8266WiFi.h>                        // ESP WiFi
#include <Wire.h>                               //
#include <SPI.h>                                //
#include <HMC5883L.h>                           // HMC5883L
#include "Adafruit_GFX.h"                       // Adafruit Grafic
#include "Adafruit_ST7735.h"                    // Adafruit ST7735
#define CS    D8                                // TFT CS  : D0 = 16
#define RST   D2                                // TFT RST : D2 =  4
#define DC    D1                                // TFT DC  : D1 =  5 
#define SCLK  D5                                // TFT SLCK: D5 = 14 
#define MOSI  D7                                // TFT MOSI: D7 = 13 
Adafruit_ST7735 tft 
  = Adafruit_ST7735( CS, DC, MOSI, SCLK, RST);  // TFT
HMC5883L compass; 
int pre_HD = 0;
float HD = 0;                                   // Heading new
float HD_old = 360;                             // Heading oled
uint16_t cx, cy;                                // center x,y
const uint16_t rad = 64;                        // radius of length
const float deg = 2 * PI / 360;                 // radian to degree
uint16_t osx, osy;
//String v = "A";                               // TFT ver A : V1.1
//String v = "B";                               // TFT ver B : V1.4 ?
  String v = "C";                               // TFT ver C : V2.1

void setup(void){
  WiFi.mode(WIFI_OFF);                          // without TELEC
  Serial.begin(115200);Serial.println();        // 
  Wire.begin(D4, D3);                           // HMC5883L SDA,SCL,D4,D3
  while (!compass.begin()){delay(500);}         // Initialize HMC5883L
  compass.setRange(HMC5883L_RANGE_1_3GA);       // Set measurement range
  compass.setMeasurementMode(HMC5883L_CONTINOUS);//Set measurement mode
  compass.setDataRate(HMC5883L_DATARATE_30HZ);  // Set data rate
  compass.setSamples(HMC5883L_SAMPLES_8);       // Set number of samples averaged
  compass.setOffset(32, -202);                  // Set calibration offset
  //--------------------------------------------// See HMC5883L_calibration.ino
  if (v == "A"){tft.initR(INITR_144GREENTAB);}  // 1.44 v1.1
  if (v == "C"){tft.initR(INITR_18GREENTAB);}   // 1.44 v2.1 
  tft.fillScreen(ST7735_BLACK);                 //
  tft.setTextColor(0x5FCC);                     // GREEN
  tft.setRotation(1);                           //
  //--------------------------------------------//
  cx = tft.width()/2; cy = tft.height()/2;      // Center Calculate
  if (v == "C" ){ cx = cx + 14; }               //
  osx = cx; osy = cy;                           //
  face();                                       // indicator face
}

void loop(void){
  Vector norm = compass.readNormalize();        // data read
  float HDG = atan2(norm.YAxis, norm.XAxis);    // Calculate HDG
  float dec_angle=(-7+(25.0/60.0))/(180/M_PI);  // Tokyo:-7.25
  HDG += dec_angle;                             // heading data
  if (HDG < 0   ){HDG += 2 * PI;}
  if (HDG > 2*PI){HDG -= 2 * PI;}
  float fixeds_HD = HDG * 180/M_PI;             // Convert to degrees to fix
 
  int smooth_HD = round(fixeds_HD);             // Smooth angles +/- 3deg
  if (smooth_HD < (pre_HD + 3) &&
      smooth_HD > (pre_HD - 3)){
      smooth_HD = pre_HD;
  }
  pre_HD = smooth_HD; HD = smooth_HD;
  Serial.print(norm.XAxis);Serial.print(":");   // Output to processing
  Serial.print(norm.YAxis);Serial.print(":");
  Serial.print(norm.ZAxis);Serial.print(":");
  Serial.print(HD);Serial.print(":");
  Serial.print(fixeds_HD );Serial.print(":");
  Serial.print(smooth_HD);Serial.println();
  delay(30); // One loop: ~5ms,115200,delay ~28ms:allow data rate 30Hz (~33ms)

  if(HD != HD_old){
    indication_Triangle();                      // Triangle indication
  //indication_Line();                          // line     indication
    indication_Dot();                           // dot      indication
    HD_old = HD;                                // old HD save
  }
  delay(250);
}

void face(){
  uint16_t xd,yd;
  tft.fillScreen(ST7735_BLACK);                 // Dsplay Clear
  tft.fillCircle(cx, cy, rad-2, 0x3CDF);        // BLUE  Ring
  tft.fillCircle(cx, cy, rad-5, 0x0000);        // BLACK
  tft.setTextSize(1);
  tft.setTextColor(ST7735_WHITE);
  xd = cos(-90 * deg) * (rad - 11) + cx;
  yd = sin(-90 * deg) * (rad - 11) + cy;
  tft.setCursor(xd-1, yd-1);tft.println("N");   // N
  xd = cos(  0 * deg) * (rad - 11) + cx;
  yd = sin(  0 * deg) * (rad - 11) + cy;
  tft.setCursor(xd-3, yd-3);tft.println("E");   // E
  xd = cos( 90 * deg) * (rad - 11) + cx;
  yd = sin( 90 * deg) * (rad - 11) + cy;
  tft.setCursor(xd-1, yd-5);tft.println("S");   // S
  xd = cos(180 * deg) * (rad - 11) + cx;
  yd = sin(180 * deg) * (rad - 11) + cy;
  tft.setCursor(xd-0, yd-2);tft.println("W");   // W
  for (int i = 0; i < 360; i += 30) {           // 12 point
    xd = cos((i - 90) * deg) * (rad - 5) + cx;
    yd = sin((i - 90) * deg) * (rad - 5) + cy;
    if ( i ==   0 ){ xd = xd + 1;}
    if ( i == 180 ){ xd = xd + 1;yd = yd + 1;}
    if ( i == 270 ){ yd = yd + 1;}
    tft.drawPixel(xd, yd, 0xFFFF);              // pixel ring
  }
  if ( v == "A" ){ apple_icon( 1,1);}           // apple icon
  if ( v == "C" ){ apple_icon(31,1);}           // apple icon
}
void apple_icon(int px,int py){                 // apple icon
  tft.drawLine(6+px, 1+py,7+px, 1+py,0x07E0);
  tft.drawLine(5+px, 2+py,6+px, 2+py,0x07E0);
  tft.drawLine(5+px, 3+py,5+px, 3+py,0x07E0);
  tft.drawLine(2+px, 4+py,8+px, 4+py,0xFFE0);
  tft.drawLine(1+px, 5+py,9+px, 5+py,0xFFE0);
  tft.drawLine(1+px, 6+py,7+px, 6+py,0xFD24);
  tft.drawLine(1+px, 7+py,7+px, 7+py,0xFD24);
  tft.drawLine(1+px, 8+py,9+px, 8+py,0xF800);
  tft.drawLine(1+px, 9+py,9+px, 9+py,0xF800);
  tft.drawLine(2+px,10+py,8+px,10+py,0x3CDF);
  tft.drawLine(3+px,11+py,4+px,11+py,0x3CDF);
  tft.drawLine(6+px,11+py,7+px,11+py,0x3CDF);
}

void indication_Triangle(){
  int cr = 41; float r = M_PI/180;
  float h1 = HD_old;
  tft.fillTriangle(                              // analog clear
    cx-cr*cos(r* h1   ),cy+cr*sin(r* h1   ),
    cx+cr*cos(r*(h1+5)),cy-cr*sin(r*(h1+5)),
    cx+cr*cos(r*(h1-5)),cy-cr*sin(r*(h1-5)),
    ST7735_BLACK);
  float h2 = HD;
  tft.fillTriangle(                              // analog draw
    cx-cr*cos(r* h2   ),cy+cr*sin(r* h2   ),     // x0,y0
    cx+cr*cos(r*(h2+5)),cy-cr*sin(r*(h2+5)),     // x1,y1
    cx+cr*cos(r*(h2-5)),cy-cr*sin(r*(h2-5)),     // x2,y2
    ST7735_RED);
  float d1,d2;                                   // deg decode
  if ((h1<=360)&&(h1>=90)){d1=90*((h1/90)-3);}   // 90-270:-180-  0
  if ((h2<=360)&&(h2>=90)){d2=90*((h2/90)-3);}   // 90-270:-180-  0 
  if ((h1<= 90)&&(h1>= 0)){d1=90*((h1/90)+1);}   //  0- 90:+180- 90
  if ((h2<= 90)&&(h2>= 0)){d2=90*((h2/90)+1);}   //  0- 90:+180- 90
  int xa = 103; if (v == "C" ){ xa = 135;}
  set_text(xa, 1, String(int(d1)), 0x0000, 1);  // digital clear
  set_text(xa, 1, String(int(d2)), 0x5FCC, 1);  // digital draw
  tft.fillCircle(cx, cy, 7, ST7735_RED);         // Circle r = 6
  tft.fillCircle(cx, cy, 3, ST7735_BLACK);
//apple_icon(64-5,64-5);
}
void set_text(int x,int y,String text,
              uint16_t color,byte size){
  tft.setTextSize(size);  tft.setCursor(x,y);
  tft.setTextColor(color);tft.print(text);
}

void indication_Dot(){
  uint16_t xa,ya,xb,yb;
  int h1 = HD_old - 90;
  int h2 = HD - 90;
  xa = sin(h1 * deg) * (rad - 8) + cx;          // ring old x
  ya = cos(h1 * deg) * (rad - 8) + cy;          // ring old y
  xb = sin(h2 * deg) * (rad - 8) + cx;          // ring new x
  yb = cos(h2 * deg) * (rad - 8) + cy;          // ring new y
  tft.fillRect(xa, ya-1, 3, 3, 0x0000);         // 9 dot clear
  tft.fillRect(xb, yb-1, 3, 3, 0x07E0);         // 9 dot draw
}

void indication_Line() {
  float h = HD - 90;
  float sx = sin(h * deg) * (rad - 18) + cx +1;
  float sy = cos(h * deg) * (rad - 18) + cy;
  tft.drawLine(osx, osy, cx, cy, 0x0000);       // Erase old positions 
  tft.drawLine(sx,  sy,  cx, cy, 0xFFFF);       // Draw  new positions           
  tft.fillCircle(cx, cy, 3, 0xFFFF);            // r = 3 Circle
  osx = sx; osy = sy;                           // Update x & y coords
}

Written by macsbug

11月 13, 2016 at 3:27 am

カテゴリー: ESP8266

GPIO Port of ESP32

leave a comment »

NANO32 の GPIO PORT を調べました。             2016.11.09

なんと言っても 最初は「Lチカ」( Blink )ですね。
そして 興味がある GPIO のダイレクト ポート アクセス はどのようにするか?
さらに 最高速はどこまででるか?

ESP32 への 期待は大きく 特に高速性 はどうなのか?
ところが 私の検証方法が間違いなのか 驚きと落胆の結果がでました。


 

準備:Nano32 + Arduino IDE ESP32

「Lチカ」( Blink ) は 定番の記述で動きます。

#define LED 16

void setup() {
  pinMode(LED, OUTPUT);
}
 
void loop() {
  digitalWrite(LED, HIGH);
  delay(250);
  digitalWrite(LED, LOW);
  delay(250);
}

 

Direct Access Port:ダイレクト ポート アクセス
_ GPIOのレジスターに直接アクセスし高速化が可能です。

ダイレクト ポート アクセス による「Lチカ」

#define GPIO *(volatile uint32_t *)0x3FF44020
#define LED 16

void setup() {
  //pinMode(LED, OUTPUT);
}
 
void loop() {
  GPIO =  BIT(LED);     // HIGH << LED;
  delay(250);
  GPIO = !BIT(LED);     // LOW  << LED;
  delay(250);
}

この中の delay() を削除すると最高速がでますが、そうはいかなかった。

参照:
1. ESP8266 の GPIO 速度:各種ボードのの最高速度と方法。
2. ESP8266 Direct Access Port で Lチカ:ダイレクト ポート アクセス方法。
3. ESP8266 で 1MHz 50%duty を出力する:ESP8266で精密な方形波を出力。

espressif.com の ESP32 Technical Reference Manual を参照します。
40 Page,  4.12  Register Summary の中程下。
GPIO_ENABLE_REG は GPIO 0-31 output enable register_REG : 0x3FF44020
と書かれています。
これは「#define GPIO *(volatile uint32_t *)0x3FF44020」と記述すると良い。

ESP8266の場合は 3つのレジスター操作が必要でした。 私の知識不足かも知れ
ませんが ESP32 の場合は 1つで動きました。
Direct Access Port:
_   不勉強ですが GPIO Resistor は以下の3つかと想像しています。
_   1. GPIO_ENABLE_REG
_   2. GPIO_FUNC5_OUT_SEL_CFG_REG
_   3. PERIPHS_IO_MUX_GPIOx_U

GPIO 16:以下の割り付けがありますが これでは動作せず。
IO_MUX_GPIO16_REG   Configuration register for pad GPIO16:0x3FF5304C
GPIO_FUNC0_OUT_SEL_CFG_REG:0x3FF4457C
Configuration for GPIO pin 0_REG:0x3FF440C8

 


高速動作の検証: digitalWrite(), delayMicroseconds() で試す。

delayMicroseconds(1); で試す、、、ところが波形がでません。

100μsec:delayMicroseconds(100); なんとか使えそうな波形。

20μsec:delayMicroseconds(20); 波形が崩れ 電圧が低くなっています
_    これでは使えません。

これでは ダイレクト ポート アクセス どころではなく 検証ができません。


 

感想:
1. ESP8266では 1μsecでも余裕で出ますが ESP32 は 1μsec では出力せず。
_  digitalWrite と delayMicroseconds(1); で出力しないとは どういう事なの
_  でしょうか?
2. これには驚きました。恐らく ESP8266 と同じアーキテクチャーでハードも
_  同様だとの認識では こういう事はありえない。
_  Port を変えてみたり Pull up 抵抗とか試しましたが 同様の為 今回は
_  こういう事だとします。というか今回の記事は間違っていて欲しい。
3. ESP32 に期待する所は 高速性ですが 今回の検証ではむしろESP8266より
_  遅い事になります。
4. CPU Frequency 160MHzで ESP8266 と変わらず。GPIO Port数は多いが
_  ESP8266 より低性能、価格はESP8266の9倍。これでは 買う価値が無い。
_  そうなると 260円 ( $2.48 ) で購入できる WeMos D1 mini で充分という事。
5. 他の方の検証や 今度の進展も含め 今回はこれくらいにしておきます。
6. ラズパイは 780MHz,,1.2GHz と羨ましくなります。
7. EspressifSystem の John Lee氏が ESP32 は 160MHz と述べている。
_  ともの技術メモ:ESP32のβ版がもうすぐリリース!?


 

Written by macsbug

11月 9, 2016 at 3:35 am

カテゴリー: ESP8266