1) bootloader - 起動の仕組みの理解 あるいは改造
ESP32 は、OTA -- Wifi からのプログラム書き換えができるらしいのだ。作ったボードは USB シリアルがないし、これを常用したいのだが、どういう仕組みなのか? 理解してないとなにもできない。
ちょっと調べただけだが、まず次のところに解説があった。
・ESP32 (4) – Flash, bootloader and FreeRTOS
ざっと説明すると、ROM 内の 1st stage ブートローダーが SPI FLASH から 2nd stage ブートローダーを読み込み実行する。2nd stage ブートローダー は、 factory app もしくは 2種類の OTA app から選択したものを読み込み起動する。OTA app が 2種類あるのは、書き込みが失敗したときの対策ができるということだろう。
2nd stage ブートローダー 0x1000
パーティションテーブル 0x8000
nvs 0x9000 24k
phy_init 0xf000 4k
factory app 0x10000 1M
基本はこんな配置らしいのだが、パーティション自体は別。app と data の2個のパーティションがあるらしい。
で、さらに調べると 2nd stage ブートローダー のソースコードが公開されていることが分かった。
・https://github.com/espressif/esp-idf/tree/master/components/bootloader/src/main
ソースコードがあるのなら、自分が使いやすいと思うブートローダーを作ることも可能だ。例えば、OTA で書き込んでそれを起動するようなものも作れそうだ。そこまでしなくとも、起動する app の 選択ロジックがどうなってるか調べるのにも役にたちそうだ。
いきなり訂正。
PART_TYPE_APP PART_SUBTYPE_FACTORY: factory app
ということ。OTA も PART_SUBTYPE_OTA_FLAG/PART_SUBTYPE_OTA_MASK で 2 種類が認識される。
さて、
dram_seg (RW) : org = 0x3FFF0000, len = 0x10000
iram_pool_1_seg (RWX) : org = 0x40078000, len = 0x8000
iram_seg (RWX) : org = 0x40080000, len = 0x400
メモリ上は、このあたりを使うらしい。といっても、そもそもどこが RAM なのか知らなかった。
512KB の SRAM は、3つのユニットに分かれている。
dbus ibus
SRAM 0 192KB 0x4007_8000 ~ 0x4007_FFFF
SRAM 1 128KB 0x3FFE_0000 ~ 0x3FFF_FFFF 0x400A_0000 ~ 0x400B_FFFF reverse order (word-wise)
SRAM 2 200KB 0x3FFA_E000 ~ 0x3FFD_FFFF
なんだか複雑でよく分からない。慣れが必要そうだ。
さて、OTA だが、実際にどう使うのか?
・http://ht-deko.com/arduino/esp-wroom-32.html
・http://www.iotsharing.com/2017/05/how-to-update-firmware-ota-for-batch-esp32.html
ここに説明と具体例があった。
要するにライブラリはあるが、app から 呼び出してやらないといけない。動かないコードを作ってしまうと、USB シリアル使っていちからやりなおし。ブートローダーに OTA 書き込み機能を付けるか、2 つ目の OTA app を OTA 書き込み専用にするか。まぁ普通に考えるとリカバリ用を作るのが妥当なのだろう。
ほぼなにもしないプログラム : 103362バイト(9% /1MB)グローバル変数 9432バイト(3% /294912)
ほぼ OTA のみの プログラム : 448515バイト(42% /1MB)グローバル変数 37380バイト(12% /294912)
448KB ! bootloader に組み込むなどとんでもなかった。OTA のコードなど知れているはずだから、FreeRTOS で 100KB , プロトコルスタックで +300KB ということなのだろうか? いずれにせよ、リカバリ用の OTA app を作って、bootloader では、どちらを起動するかのロジックをいじるってのが良さそう。
ちなみに ホスト側のアプリは用意する必要はなく、Arduino IDE から書き込めるようになっているらしい。そうであれば、環境さえ整えれば、USB シリアルレスで いけそうだ。
さて、実際になにをしたいか?
1) IP カメラ
まぁ取り立てて必要というわけではないが、車のバックカメラなんかは、あると良いかも知れない。
・https://github.com/igrr/esp32-cam-demo/blob/master/components/camera/ov7725.c
このサンプルコードを見ながら、いろいろやってみたいとは思う。
・Orange pi 用カメラ
ov7725 は fifo なしのを使う。だが割と高い。どうせなら、より高機能な ov2640 を使ったほうが良いかもしれない。幸いなことに Orange pi 用が割と安い --- 送料込み $8.28 (OPi を買うついでに set にしておくと $5 分ぐらい)。 実験用なら、やっすい ov7670 が良いかも知れない。ov7670 にもいろいろあって、24-pin フレキのタイプもある。互換性があるなら、ov2640 と入れ替えてテストするとかできるかも。
さて、aliexpress のカメラモジュールを見ているといろいろなタイプがある。ONVIF 対応の IP カメラが $10 ほどで買えたりする。さすがに、こういうのに対抗するのは難しいような。シリアルインターフェイスの jpeg 30fps のものもある。プロトコルは、vimicro VC0706 プロトコルというもの。先人が これを ESP8266 で IP camera にするようなことをしている。互換性があるものを作れたら良いのかも知れない。
データシートを見ていたら、ov2640 は圧縮エンジンが付いている。JPEG stream がいけるとなると、ONVIF 対応も可能? やはりこちらが本命か。
ov7670 の ピンアサイン は、aitendo のモジュールのデータシートに記載されているものが一般的なようだ。HDR というシルクがある ov7725 も同じ。そして、Orange pi カメラもおそらく同じ。ただし、電源回りは少し違うようだ。ov7670/ov7725 は、内蔵レギュレータがあり、レジスタの設定で ON/OFF できる。ov2640 もあるのだが物理的に配線が必要で、ON/OFF がレジスタではできない。もし配線されてなければ、core に 1.2v を供給しないといけない。
1 NC
2 NC
3 D2
4 D1
5 D3
6 D0
7 D4
8 PCLK
9 D5
10 GND
11 D6
12 MCLK
13 D7
14 VCC (2.8v)
15 VCORE (1.8v - ov7670/ov7725, 1.2v - ov2640)
16 HSYNC
17 STBY_EN (PWDN)
18 VSYNC
19 RESET#
20 SCK
21 AVCC (2.8v)
22 SDA
23 AGND
24 NC
ところで、これらカメラモジュールは 38mm 角のものが多い。なにか規格があるのだろうか? カメラ専用基板とか作りたくなっているので気になる。

ELECROW が SALE をしているので、基板を作りたく。10cm x10cm 5枚だと、$4.9 + 送料 $6.42 の $11.32 で作成できる。で、ESP32 基板にカメラ用コネクタを追加したものを作成してみた。
・suzbrd_wroom32_v1.2-out.zip -- 提出ファイル
・suzbrd_wroom32_v1.2.zip -- eagle ソース
カメラの信号の割り当て
1 NC
2 NC
3 D2 IO14
4 D1 IO12
5 D3 IO13
6 D0 IO15
7 D4 IO16
8 PCLK IO17
9 D5 IO4
10 GND
11 D6 IO35
12 MCLK IO5
13 D7 IO18
14 VCC (2.8v)
15 VCORE (1.8v - ov7670/ov7725, 1.2v - ov2640)
16 HSYNC IO19
17 STBY_EN (PWDN) pull-down
18 VSYNC IO21
19 RESET# IO2
20 SCK IO23
21 AVCC (2.8v)
22 SDA IO22
23 AGND
24 NC
こんな割り当て、VCORE には 3端子レギュレーターを付けることが可能で、AVCC は LC フィルタを通して供給するようにした。それは良いのだが、余ってる I/O はかなり少ない。この形状にする必要はあったのか?少々疑問ではある。
ところで、SOT23 のレギュレーターをパターンに入れたが、適合するのがあまりない。MCP1700 もしくは、AP2120N ぐらい。内部レギュレータがあるのに、必要なのか?という疑問があるのだが、OV2640 のモジュールは、普通レギュレータが 2つ 3つ載っている。3.3V → 2.8v とかがまずひとつ。2つあるってことは、3.3v → 1.2v なんだろう。3つあるやつは、AVCC かな。さて、OV7670 は内部レギュレータがあって ON/OFF できる。ちなみに、VOUT に高い電圧がかかった場合、なにも起きないはずなので、OV7670 に切り替えてテストする場合も1.2V レギュレータを付けておけば良いのだと思う。
ところで、サーボモータで制御するカメラ台というものがある。

このカメラをマウントする部分につめがあるが、どうも 10mm高 3cm x3cm のカメラモジュール用らしい。これに直接マウント可能なカメラ基板を作ってみたいような。サーボ制御用のコネクタも付けてしまえば、電源ケーブルだけのシンプルなものになる。だだ、そこまでやるなら、カメラをちゃんと動作できてソフト開発も完了してから。幸い最近木工を覚えた。多分、桐まないたの端材でマウンタを作れば上記の基板でもいけるだろう。
あと、サーボに SG90/MG90S は使えるようだが、どうもきっちり適合しない。ひょっとして ES08MA II が適合するのかも。(間違い)。MG90S や ES08MA II は問題ないのだが、SG90 は、静止に問題があるかも知れない。カメラ用としては致命的。できれば 避けたほうが良いのかも。
2017/7/5 追記

Orange pi i96 というボードが出た。価格 $8.8 + 送料、サイズ 60mm x 30mm 。Wifi+Bluetooth とカメラインターフェイス。おそらくだが、カメラインターフェイスは、今までの OPi シリーズと違って、上記のカメラモジュールが直接接続できる。今までは 電源を直接供給しておらず、変換ボードが必要だった。が、2G IOT から、2.8v と 1.8v を供給するようになった。i96 も 同じ SoC RDA 8810PL 採用なので、カメラについても同じだと思われる。

2G IOT の回路図はこうなっている。1.8V / 2.8V は、RDA 8810PL が供給しているようだ。この 1.8V がプログラマブルならば、ov2640 も接続できるかも知れない。
あと気になったところは、AVDD 。 10Ω + 10uF の RC LPF で済ませている。 設計した ESP32 は LC LPF を付けているが、時定数が適当だったので、見直してみたい。
さて、このようなボードが出てくるとなると、作ろうと思っているカメラボードについて再考しないといけないかも知れない。というか OPi i96 がカメラボードそのものに見える --- これ使えば良いじゃないと思えて来てしまうのである。
2) bluetooth スピーカー あるいはイヤホン
bluetooth のデバイス作れるのだから当然やってみたい。このあたりは先人が既に作っているから、楽だろう。慣れるために手を付けたいわけなので、外部 DAC じゃなくて、内蔵 DAC もしくは、1bit シグマデルタでやりたい。シグマデルタは GPIO を叩くライブラリがあったはず。RMT を使ったものはまだないかも知れない。
・事:ESP32でBluetoothイヤホンを作ってみた – Qiita
・ESP32でI2S+DACを使う – Qiita
・https://github.com/espressif/esp-idf/tree/master/examples/bluetooth
このあたり。
3) bluetooth キーボード
キーボードというか HID デバイスを作りたい。自由に作れるようになれば、かなり応用が広がる。ゲームコントローラに仕込んで、なにか遠隔操作するとか。あるいは、Android を遠隔操作するものとか -- 赤外線ハンドルリモコンのブリッジとか。
HOGP -- HID over GATT Profile を使うらしいのだが、あまり情報がない。誰かの実装まち。
bluetooth には Classic (いわゆるプロファイル) と BLE があり、HOGP などは BLE に属する。classic にも HID プロファイルがある。この2つは別物で、とりあえず HID プロファイルが使えれば嬉しいのだが、どうやって作るものなのか? HCI Command というのを理解すれば良い?ちょっと調べてみよう。
・https://www.bluetooth.com/ja-jp/specifications/adopted-specifications/legacy-specifications
・http://www.yts.rdy.jp/pic/GB002/GB002.html
先人が PIC+USBドングルのコードを作って解説してくれている。おおいに参考になりそう。
4) その他 bluetooth デバイス
bluetooth デバイス はまだまだある。USB シリアルの代替につかえる bluetooth シリアル とか。
・http://anoda.cocolog-nifty.com/mad/2017/06/esp-wroom-32blu.html
SPP が使用可能になったそうだ。
ところで、USB シリアルの代替ならば、Wifi でもいい。
・http://www.eterlogic.com/Products.VSPE.html
Virtual Serial Ports Emulator なるソフトは、Windows から COM ポートとして接続してくれるので、既存のソフトが使えるようになる。例えば 中華CNCのコントローラは、Arduino だったりするので、代替できるものが作れるかも知れない。
というか、もし中華CNCを買うなら、代替コントローラ作ってみたい。まずは、無線化した同等機能。できれば、モータの回転数をモニタして、過負荷を検出 -- 動かす速度を落とす...みたいな機能とか。あとは、原点を検出するような機能とか。さらに言うと材料との位置合わせのためのなにか?
ググってみると、原点検出は標準的な機能らしい。透過型フォトセンサなどを取り付けている人がいた。Z軸はより容易なようだ。テーブルの精度(高低)を測定したりも可能。自機で削って公正している例もあった。また材料との位置合わせのためにUSBスコープを取り付けてる例もあった。モータの回転数も測定してる人はいた。これをフィードバックして制御するような例だけ見つからなかった。
顕微鏡まで付けるとなると ... 1台のESP32 では荷が重い。じゃぁ2台? CNC が既にある前提なら 顕微鏡すら自作できるかも知れないし。
5) lowspeed USB HOST/device
ESP8266 でも ソフトUSB ができるそうだが、ESP32 でもたぶんできるのだろう。そのためには、CPU を1つ占有してブン回さないと。
・https://techtutorialsx.com/2017/05/09/esp32-running-code-on-a-specific-core/
とりあえず、コア指定でタスクを動かす方法。これが出来たうえで、同一バンクへのメモリアクセスが競合しないようにする。そこまでできれば、ESP8266 と同じ条件になるはず。あるいは、RMT を使うとか。
ADC についてのメモ
ADC は2つある。ひとつは、ADC1 で 低ノイズアンプあり。あと ADC2 。ADC のピンは、どちらかに接続されている。
ADC を制御するコントローラは、RTC ドメインと、DIGTAL ドメインにある。RTC ADC1, ETC ADC2, DIG ADC1,DIG ADC2 の4つ。なんだかよく分からないが、RTC ドメインの方は、ulp 用だと思っておこう。DIGTAL ドメインの方は、高速で 複数チャネルのスキャンもサポートしている。
また、ADC に接続される内部機能がある。ホールセンサ、電源電圧(PWDAT)、および 電源のピーク電圧(PKDAT)。それ以外に温度計があり、こちらは専用の ADC に接続されている。
SENSOR_VP (GPIO36)
SENSOR_CAPP (GPIO37)
SENSOR_CAPN (GPIO38)
SENSOR_VN (GPIO39)
32K_XP (GPIO33)
32K_XN (GPIO32)
VDET_1 (GPIO34)
VDET_2 (GPIO35)
これらは、ADC1 に接続されている。またホールセンサは、SENSOR_VP/SENSOR_VN に接続されている。
その他は ADC2 である。
さて、DIG ADC は、どれぐらい高速なのか? 調べて 11us とか 17.2 us とか書いている人がいてはっきりしない。analogRead()を使っての計測で、ピンの設定やらなにやらをいちいちやっての時間らしい。
esp32-hal-adc.h
/*
* Set number of cycles per sample
* Default is 8 and seems to do well
* Range is 1 - 255
* */
void analogSetCycles(uint8_t cycles);
/*
* Set the divider for the ADC clock.
* Default is 1
* Range is 1 - 255
* */
void analogSetClockDiv(uint8_t clockDiv);
どうやら、ADC clock は クロックソースを分周して、指定したクロック数かけて計測するようだ。しかし、クロックソースが何かは良くわからない。
adc.h
/**
* @brief Set ADC source clock
* @param clk_div ADC clock divider, ADC clock is divided from APB clock
* @return
* - ESP_OK success
*/
esp_err_t adc_set_clk_div(uint8_t clk_div);
こっちに書いてあった。APB_CLK というのは、80MHz (最大) 。div が 1 というのは、1/1 分周? だとしたら 80MHz で 8 clock で取得できるのだから 10M sps ? 最適な値を設定しなければ、精度に差がでてしまうのだろうが、結構すごいような。AVR とは雲泥の差である。
ただし、正確な起動タイミングというのが、少々怪しい。ソフトウェアかまたは I2S と書いてある。ソフトウェアでは、完全に正確なタイミングは取れない。となると I2S になるのだが ...
I2S には、ADC モードというのがある。ADC のデータを取得して I2S で外部に出力する機能。( ちなみに、DAC モードというのもある。I2S から入力したデータを DAC で出力する。)。これのために起動できるようになっているのだが、内部に取り込むために使えるのかどうか不明。
ついでだが、audio clock というのが独立して存在する。専用のPLL で I2S だけが使用できる。44.1k の整数倍とか サウンド用の周波数を作り出すためのもの。それは良いのだが、完全に正確なタイミングとなると無理。
さて、DAC はどういうものなのか? 8bit x 2 というのはすぐ分かるが、周波数などは?
まず フルスケールは、電源電圧の 3.3V -- ではあるが、4 段階のスケーリング 1/1, 1/2, 1/4, 1/8 が出来る。 うまく使えば 12bit 相当になるかも。クロックについては、ソースが RTC8M_CLK (8MHz) でこれの n/65536 (n = 1 〜 65536) とか。PLL を 使っているのだろうか? とにかく最大は 8MHz のようだ。1 クロック毎に出力できるとは思えないのだが詳細は分からない。仮に 8 clock だとしても 1M sps になる。これだと、多値 ΣΔ とかで 8bit 以上の分解能を実現することが可能かも知れない。ただし、電源にノイズが乗れば、だいなしである。ESP-WROOM-32 なんかだと、電源も1つにまとめられているので、厳しい。
基板づくりメモ
先日はじめて ELECROW を使ってみた。使ったのは、special offer というので、10cm x10cm 10枚が、$9.5 +送料 $3.3 =$12.8 で作れた。(今は送料$4.8 計$14.3) 。AIR MAIL でも 2週間かからなかったし、シルクの品質にも満足。さらに今は、5 枚までなら、カラー基板がさらに安くなっている。
https://www.elecrow.com/5pcs-2-layer-pcb.html
$4.9 が基本価格で、送料は 5cm x5cm $3.72 , 5cm x10cm $4.98, 10cm x10cm $6.42 。
milling を使った疑似パネライズが OK らしいので、便利に使えそう。