M5Stackとフォント ランレングス(RUN LENGTH ENCODING)への対応 [ESP32]
前回ではランレングスのデコード方法が判らなかったので、非圧縮フォントデータのみ扱いましたが、今回はデコード方法が判ったのでそれに対応しました。
一応フォントデータのデコード方法ですが、例えばFont32rle.cを見てみると
widtbl_f32[96]と言う配列、chr_f32_20[]と言う配列、chrtbl_f32[96]と言う配列が有る訳ですが、
widtbl_f32はその文字の横幅を示しています。最初の値はASCIIコードでスペースなのですが、そのスペースの横幅はこの場合5ピクセルです。
chr_f32_20は文字のビットパターンで、ここがランレングスで圧縮されています。配列名の最後の2文字はASCIIコード番号を示し、この場合はスペースの20(16進)です。
chrtbl_f32は上記ビットパターンのポインターの配列です。
なので文字の横幅を知りたい時は、ASCIIコード番号からオフセット分を引いた値をwidtbl_f32配列のインデックスにすればアクセスできますし、ビットパターンを知りたい時はASCIIコード番号からオフセット分を引いた値をchrtbl_f32配列のインデックスにすればアクセスできます。
ランレングスのデコードですが、ビットパターンのそれぞれの1byte単位のデータに着目してみます。
例えばASCIIコードでスペースの値は以下です。
1byteのデータの最上位ビットが色の情報であり、例えば最上位に1が立っていれば1ピクセル表示する。1が立っていなければ1ピクセルの表示は行わないとします。(逆でも構わない)
続く7bitはその色情報が続く長さを示し、0から127までの値を取りえますが、実際はその値に1を加算します。
上記の0x7F, 0x1であれば、127+1+1+1=130ピクセル分表示しない事になります。
さて横幅は5ピクセルですので、130を5で割れば26となり、26は文字高さになります。
実際はこの値はFont32rle.hの中で定義されていますので、この定義を利用する方が良いでしょう。
さて、ランレングスのデコード方法が判ったので、実際にLCDに表示させてみました。
フォントサイズが32まではそれなりにASCIIコードが表示されますが、それ以上のサイズのフォントはまともに表示できるのは数字のみの様です。
ROMサイズをケチったのか?それとも面倒臭かったのか?
ESP32 Arduinoのプロジェクトを置いておきます。
https://1drv.ms/u/s!AgxfaDqma1yrhk6AY-NUsBh7pyXb
※追記
M5Stackの組み込みフォントのヘッダーファイル、例えばFont32rle.hは再帰呼び出しに対応していないので、ファイルの先頭と最後に以下の様な#ifdef文を追加します。Font32rle.hの例。
一応フォントデータのデコード方法ですが、例えばFont32rle.cを見てみると
widtbl_f32[96]と言う配列、chr_f32_20[]と言う配列、chrtbl_f32[96]と言う配列が有る訳ですが、
widtbl_f32はその文字の横幅を示しています。最初の値はASCIIコードでスペースなのですが、そのスペースの横幅はこの場合5ピクセルです。
chr_f32_20は文字のビットパターンで、ここがランレングスで圧縮されています。配列名の最後の2文字はASCIIコード番号を示し、この場合はスペースの20(16進)です。
chrtbl_f32は上記ビットパターンのポインターの配列です。
なので文字の横幅を知りたい時は、ASCIIコード番号からオフセット分を引いた値をwidtbl_f32配列のインデックスにすればアクセスできますし、ビットパターンを知りたい時はASCIIコード番号からオフセット分を引いた値をchrtbl_f32配列のインデックスにすればアクセスできます。
ランレングスのデコードですが、ビットパターンのそれぞれの1byte単位のデータに着目してみます。
例えばASCIIコードでスペースの値は以下です。
PROGMEM const unsigned char chr_f32_20[] = { 0x7F, 0x1 };
1byteのデータの最上位ビットが色の情報であり、例えば最上位に1が立っていれば1ピクセル表示する。1が立っていなければ1ピクセルの表示は行わないとします。(逆でも構わない)
続く7bitはその色情報が続く長さを示し、0から127までの値を取りえますが、実際はその値に1を加算します。
上記の0x7F, 0x1であれば、127+1+1+1=130ピクセル分表示しない事になります。
さて横幅は5ピクセルですので、130を5で割れば26となり、26は文字高さになります。
実際はこの値はFont32rle.hの中で定義されていますので、この定義を利用する方が良いでしょう。
さて、ランレングスのデコード方法が判ったので、実際にLCDに表示させてみました。
フォントサイズが32まではそれなりにASCIIコードが表示されますが、それ以上のサイズのフォントはまともに表示できるのは数字のみの様です。
ROMサイズをケチったのか?それとも面倒臭かったのか?
ESP32 Arduinoのプロジェクトを置いておきます。
https://1drv.ms/u/s!AgxfaDqma1yrhk6AY-NUsBh7pyXb
※追記
M5Stackの組み込みフォントのヘッダーファイル、例えばFont32rle.hは再帰呼び出しに対応していないので、ファイルの先頭と最後に以下の様な#ifdef文を追加します。Font32rle.hの例。
#ifndef FONT32RLE_h #define FONT32RLE_h #include#define nr_chrs_f32 96 #define chr_hgt_f32 26 #define baseline_f32 19 #define data_size_f32 8 #define firstchr_f32 32 extern const unsigned char widtbl_f32[96]; extern const unsigned char* const chrtbl_f32[96]; #endif /*FONT32RLE_h*/
M5Stackとフォント [ESP32]
M5Stackの標準ライブラリでprintメソッドを使った場合、結構文字が小さく表示されます。
しかしライブラリのソース(In_eSPI_Setup.h)を見てみると実際に利用可能なフォントは複数あります。
#define LOAD_GLCD // Font 1. Original Adafruit 8 pixel font needs ~1820 bytes in FLASH #define LOAD_FONT2 // Font 2. Small 16 pixel high font, needs ~3534 bytes in FLASH, 96 characters #define LOAD_FONT4 // Font 4. Medium 26 pixel high font, needs ~5848 bytes in FLASH, 96 characters #define LOAD_FONT6 // Font 6. Large 48 pixel font, needs ~2666 bytes in FLASH, only characters 1234567890:-.apm #define LOAD_FONT7 // Font 7. 7 segment 48 pixel font, needs ~2438 bytes in FLASH, only characters 1234567890:. #define LOAD_FONT8 // Font 8. Large 75 pixel font needs ~3256 bytes in FLASH, only characters 1234567890:-. //#define LOAD_FONT8N // Font 8. Alternative to Font 8 above, slightly narrower, so 3 digits fit a 160 pixel TFT #define LOAD_GFXFF // FreeFonts. Include access to the 48 Adafruit_GFX free fonts FF1 to FF48 and custom fonts
LOAD_GLCDがおそらくprintメソッドで利用されるフォントです。上記の写真の上半分の文字がそれです。小さいですね。
LOAD_FONT2以降をprintメソッドから利用する方法が見つかりません。drawCentreStringやdrawRightStringからは引数に数字でフォントを指定すれば画面上に表示されます。
しかしdrawCentreStringやdrawRightStringはラベル等で利用する事を目的としたのか、改行は利きませんので、長文はうまく行きません。
LOAD_FONT2のフォント(Font16.c)のみ、画面に出力するライブラリを作成してみました。
https://1drv.ms/u/s!AgxfaDqma1yrhk6AY-NUsBh7pyXb
他のフォントはRLE(RUN LENGTH ENCODING)されており、ちょっとデコードの方法が判らなかったので対応していません。
標示した長文が一番上の写真の下側の黄色い文字です。文章が改行されている事が判ります。
これらのフォントはプロポーショナルフォントの様です。比較的見栄えの良い表示が出来ていると思います。
M5Stackのソースには上記プロポーショナルフォント以外に等幅フォントがありました。5×7のフォントで、表示させてみたのが下の写真です。
ところで標準のprintライブラリってこっちが作成したライブラリに比較して文字の表示が圧倒的に速いじゃないですか、あれ、ソースコードを見てみると、直接SPIでLCDにビットデータを転送しているのね!
M5StackとMLX90640 [ESP32]
IoTLTで登壇を申し込みました。
https://iotlt.connpass.com/event/124544/?fbclid=IwAR20sd0yigJlk1trNuqP-CdMaMHmnPK10GJ8I9jpyvdpOI_juDaeaEmuHhY
表示させてみた。MLX90640はマルツで税込で6000円弱で購入可能。実際にはデジキにオーダーされる!
MLX90640のメリットは、FLIRと比較して安価で入手が容易な事、測定温度範囲が広い事。
デメリットはFLIRと比較して解像度がだいぶ低い事。
FLIRをデジキで買った時はたいへんだった。まずアメリカの輸出規制に引っ掛かるので、アメリカ政府に軍事目的じゃなく民間利用ですよ~って申請書類を書かねばならない。しかも実際に輸出されるまで長い事、長い事。忘れた頃に発送の通知が来る。たぶん今、アメリカ政府の機関が予算の関係で動いていないので、もっと時間掛かるに違いない!
kicadのプロジェクト(回路図込み)
https://1drv.ms/u/s!AgxfaDqma1yrhkzz561J0Jj7Bng5
と、とりあえずサーモグラフィー表示をするソースコード
https://1drv.ms/u/s!AgxfaDqma1yrhkzz561J0Jj7Bng5
部品表
https://1drv.ms/x/s!AgxfaDqma1yrhk3DE9TKJ_fgpOgd
を公開しました。
省電力でも使える?ように3.3Vと5V電源を操作できるようにしてあります。
MLX90640のライブラリはgitHubで公開しているライブラリを利用しています!(ソースの先頭にライセンスを貼り付け)
基板はPCBGOGOで注文すれば、凄く安く、かつ早く作ってくれます。
基板に注意点があります。
1.うっかりしていましたが、5V電源のFETスイッチのR17は抵抗ではなく青色LEDを実装してください。基板下側がカソードです。
2.LED1、LED2も基板下側がカソードです。
3.MLX90640は円柱形の根本のタブが下側になります。
※こう言うのをWEBブラウザ上で背景の写真とオーバーレイで表示するJava scriptとか知っていたら教えて欲しい。
二枚目は液晶テレビを撮影。右側に電源が有るのかな?
https://iotlt.connpass.com/event/124544/?fbclid=IwAR20sd0yigJlk1trNuqP-CdMaMHmnPK10GJ8I9jpyvdpOI_juDaeaEmuHhY
表示させてみた。MLX90640はマルツで税込で6000円弱で購入可能。実際にはデジキにオーダーされる!
MLX90640のメリットは、FLIRと比較して安価で入手が容易な事、測定温度範囲が広い事。
デメリットはFLIRと比較して解像度がだいぶ低い事。
FLIRをデジキで買った時はたいへんだった。まずアメリカの輸出規制に引っ掛かるので、アメリカ政府に軍事目的じゃなく民間利用ですよ~って申請書類を書かねばならない。しかも実際に輸出されるまで長い事、長い事。忘れた頃に発送の通知が来る。たぶん今、アメリカ政府の機関が予算の関係で動いていないので、もっと時間掛かるに違いない!
kicadのプロジェクト(回路図込み)
https://1drv.ms/u/s!AgxfaDqma1yrhkzz561J0Jj7Bng5
と、とりあえずサーモグラフィー表示をするソースコード
https://1drv.ms/u/s!AgxfaDqma1yrhkzz561J0Jj7Bng5
部品表
https://1drv.ms/x/s!AgxfaDqma1yrhk3DE9TKJ_fgpOgd
を公開しました。
省電力でも使える?ように3.3Vと5V電源を操作できるようにしてあります。
MLX90640のライブラリはgitHubで公開しているライブラリを利用しています!(ソースの先頭にライセンスを貼り付け)
基板はPCBGOGOで注文すれば、凄く安く、かつ早く作ってくれます。
基板に注意点があります。
1.うっかりしていましたが、5V電源のFETスイッチのR17は抵抗ではなく青色LEDを実装してください。基板下側がカソードです。
2.LED1、LED2も基板下側がカソードです。
3.MLX90640は円柱形の根本のタブが下側になります。
※こう言うのをWEBブラウザ上で背景の写真とオーバーレイで表示するJava scriptとか知っていたら教えて欲しい。
二枚目は液晶テレビを撮影。右側に電源が有るのかな?
ESP32 で2つ目のI2Cを動かすメモ的な何か? [ESP32]
#include <Wire.h> #define I2C_HERTZ (100 * 1000) #define SDA_PIN 25 #define SCL_PIN 26 #define I2C1_HERTZ (100 * 1000) #define SDA1_PIN 17 #define SCL1_PIN 16 TwoWire i2c1( 1 ); void setup() { Wire.begin( SDA_PIN, SCL_PIN ); // Wire.begin( SDA, SCL ); Wire.setClock( I2C_HERTZ ); // default = 100kbps i2c1.begin( SDA1_PIN, SCL1_PIN ); i2c1.setClock( I2C1_HERTZ ); // default = 100kbps } void loop() { }
ESP32 サーモグラフィーセンサー グラフ化 [ESP32]
Ambientの公開チャネルで公開、、、
https://ambidata.io/ch/channel.html?id=4538
FeatherWing - AMG8833搭載 赤外線サーマルカメラ
- 出版社/メーカー: スイッチサイエンス
- メディア: おもちゃ&ホビー
ESP32のシステムタイマーの値を取得する。 [ESP32]
Arduinoで起動時からの経過時間を取得する関数としてmillisがありますが、戻り値が32bit長なので49日程度でオーバーフローしてしまい、起動時からの経過時間として利用する事は向かない。
μITRONであれば32bit+16bit長のシステムタイマーで9000年くらいオーバーフローしないで済む話ですが、ESP32 ArduinoもRTOSな訳ですから、そこは充分な長さのタイマーを持っている事をここでちょっと紹介しています。
https://hamayan.blog.so-net.ne.jp/2018-02-18-2
freeRTOSの高精度タイマーはライブラリとして提供されており、詳細は以下のリンクを参照して下さい。
https://docs.espressif.com/projects/esp-idf/en/latest/api-reference/system/esp_timer.html#obtaining-current-time
μs単位で64bit長のタイマーがあり、つまり29000年くらいオーバーフローしない?
μITRONであれば32bit+16bit長のシステムタイマーで9000年くらいオーバーフローしないで済む話ですが、ESP32 ArduinoもRTOSな訳ですから、そこは充分な長さのタイマーを持っている事をここでちょっと紹介しています。
https://hamayan.blog.so-net.ne.jp/2018-02-18-2
freeRTOSの高精度タイマーはライブラリとして提供されており、詳細は以下のリンクを参照して下さい。
https://docs.espressif.com/projects/esp-idf/en/latest/api-reference/system/esp_timer.html#obtaining-current-time
μs単位で64bit長のタイマーがあり、つまり29000年くらいオーバーフローしない?
ESP32のdelay挿入。そんな訳はない [ESP32]
某ミニブログで、「Arduino - ESP32でdelay(1)を挿入してもWDTが入るので、delay(10)くらいにしないとダメだ!」みたいなのがリツィートされてきたけれど、そんな訳ない!
もしそんな状況であれば、みんな一度はやるGPIOでポートをバタバタさせる最大周波数は幾つ?なんて実験できなくなる。
試しにsetupの中とかで、なんにもしない無限ループとか入れてみればイイ。
ESP32はESP8266ではないので、delayへの依存性は無い。
※追記
上記の件はどうもCore0側の話で、 https://hamayan.blog.so-net.ne.jp/2018-02-21 でやった事だとは思う。
WDTにはいろんな種類があって、いきなりハードウエアリセットしてしまうものから、ソフトウエアの実行時間の上限及び下限を監視するものとかあり、上記リンクの場合はソフトウエアの実行時間の上限(または下限)設定に引っ掛かっているのではないだろうか?
この場合割り込みが入ってカーネル(特権モード)が上限を超えた事に対してなんらかのアクションを取る事になる、、、と思われる。
※エラーメッセージではCORE0側のIDLEタスクがリセットできなかった!となっているので、WDTリセットはIDLEタスクが行っている可能性が高い。
対策は、Wifiなどのシステム関連の処理を行っているであろうCore0側に傍若無人なプログラムを置かず、廻りと協調して動くことだと思う。可能な限りユーザーアプリケーションはCore1側で実行し、適切なタスク分割が必要でしょう。
別にdelay(vTaskDelay)でなくてもfreeRTOSが提供しているAPIの内、待ち状態に遷移するAPI(イベント待ちとか、セマフォとか、データキューとか色々)を利用すればIDLEタスクにCPU時間が与えられる可能性が高くなるので、積極的にfreeRTOSのAPIを利用して行こう!
もしそんな状況であれば、みんな一度はやるGPIOでポートをバタバタさせる最大周波数は幾つ?なんて実験できなくなる。
試しにsetupの中とかで、なんにもしない無限ループとか入れてみればイイ。
ESP32はESP8266ではないので、delayへの依存性は無い。
※追記
上記の件はどうもCore0側の話で、 https://hamayan.blog.so-net.ne.jp/2018-02-21 でやった事だとは思う。
WDTにはいろんな種類があって、いきなりハードウエアリセットしてしまうものから、ソフトウエアの実行時間の上限及び下限を監視するものとかあり、上記リンクの場合はソフトウエアの実行時間の上限(または下限)設定に引っ掛かっているのではないだろうか?
この場合割り込みが入ってカーネル(特権モード)が上限を超えた事に対してなんらかのアクションを取る事になる、、、と思われる。
※エラーメッセージではCORE0側のIDLEタスクがリセットできなかった!となっているので、WDTリセットはIDLEタスクが行っている可能性が高い。
対策は、Wifiなどのシステム関連の処理を行っているであろうCore0側に傍若無人なプログラムを置かず、廻りと協調して動くことだと思う。可能な限りユーザーアプリケーションはCore1側で実行し、適切なタスク分割が必要でしょう。
別にdelay(vTaskDelay)でなくてもfreeRTOSが提供しているAPIの内、待ち状態に遷移するAPI(イベント待ちとか、セマフォとか、データキューとか色々)を利用すればIDLEタスクにCPU時間が与えられる可能性が高くなるので、積極的にfreeRTOSのAPIを利用して行こう!
(続)ESP32のLEDCについて調べてみた。 [ESP32]
某SNSで、LEDCで16チャネル分のPWM出力した時、チャネル8以降でDutyを0に設定してもLOWにならない!と言う話。その後
https://www.facebook.com/groups/927623023964478/permalink/2015391691854267/
件のコードは以下。
前回は秋月で3450円で売っている簡易オシロ( http://akizukidenshi.com/catalog/g/gM-12972/ )で確認した。このオシロではDuty=100%時になんかヒゲが出ている事は確認している。
今回はもう少しましなオシロ( http://akizukidenshi.com/catalog/g/gM-10135/ )で確認してみる。
チャネル8の出力で、Duty=100%と0%の両方で止めてみた波形が以下
Duty=100%
Duty=0%
ともにおよそ15μsのヒゲが出ている事が観測される。またDuty=100%ではLOWに落ち切らず、800mVくらいオフセットが出ている。
※15μsは、PWM周波数が256Hz、分解能が8bitからであろう。
※どうも8bit分解能ではDuty=100%にする為には256を設定しないとダメみたいだ。0~256???
※Duty=0%にしてもLOWに落ち切らない現象はチャネル8(以降?)で発生する。
※件の問題の原因がこれかどうかは判らない。
※しかしこれはライブラリのバグでしょう!
※esp32-hal-ledc.cのledcWriteを見てみると、
チャネル8が所属するグループ1側は値の変更に対して、チャネル0~7のグループ0はクロックの停止をしている?なぜグループで対応が異なるのかは判らない。
※githubでも報告されていますねん!
https://github.com/espressif/arduino-esp32/issues/1909
https://www.facebook.com/groups/927623023964478/permalink/2015391691854267/
件のコードは以下。
#define L1 27 #define L15 2 void setup() { Serial.begin(9600); pinMode(L1,OUTPUT); ledcSetup(0, 256, 8); ledcAttachPin(L1, 0); pinMode(L15,OUTPUT); ledcSetup(8, 256, 8); ledcAttachPin(L15,8); delay(10); } void loop() { for(int vr = 0; vr <= 255; vr++) { ledcWrite(0,vr); ledcWrite(8,vr); Serial.println(vr); delay(10); } delay(2000); for(int vr = 255; vr >= 0; vr--) { ledcWrite(0,vr); ledcWrite(8,vr); Serial.println(vr); delay(10); } delay(5000); }
前回は秋月で3450円で売っている簡易オシロ( http://akizukidenshi.com/catalog/g/gM-12972/ )で確認した。このオシロではDuty=100%時になんかヒゲが出ている事は確認している。
今回はもう少しましなオシロ( http://akizukidenshi.com/catalog/g/gM-10135/ )で確認してみる。
チャネル8の出力で、Duty=100%と0%の両方で止めてみた波形が以下
Duty=100%
Duty=0%
ともにおよそ15μsのヒゲが出ている事が観測される。またDuty=100%ではLOWに落ち切らず、800mVくらいオフセットが出ている。
※15μsは、PWM周波数が256Hz、分解能が8bitからであろう。
※どうも8bit分解能ではDuty=100%にする為には256を設定しないとダメみたいだ。0~256???
※Duty=0%にしてもLOWに落ち切らない現象はチャネル8(以降?)で発生する。
※件の問題の原因がこれかどうかは判らない。
※しかしこれはライブラリのバグでしょう!
※esp32-hal-ledc.cのledcWriteを見てみると、
チャネル8が所属するグループ1側は値の変更に対して、チャネル0~7のグループ0はクロックの停止をしている?なぜグループで対応が異なるのかは判らない。
※githubでも報告されていますねん!
https://github.com/espressif/arduino-esp32/issues/1909
ESP32のLEDCについて調べてみた。 [ESP32]
某SNSで、LEDCで16チャネル分のPWM出力した時、チャネル8以降でDutyを0に設定してもLOWにならない!と言う話があって、ちょっとLEDCについて調べてみた。
なので以下の様なコードを書いてお確かめ。
ESP32_LEDC_TEST.ino
led.h
led.c
チャネル0のみ1000HzでDuty=50%の波形を出力してみると以下の波形となった。
次に全16チャネルを出力させてみた。その時のチャネル0の波形が以下である。
お判り頂けたであろうか?PWM周波数が変わってしまっている。
以下はesp32_hal_ledc.cの一部抜粋である。
チャネル0とチャネル1は同一タイマーとなっている、、、ようするにチャネル0とチャネル1間では、後から設定した方が有効となってしまう。そりゃそうだ、、、
またチャネル0からチャネル7までと、チャネル8からチャネル15までで異なるグループとなっている。これはグループ0が80MHzを原振とする高速側のタイマー、グループ1が1MHz?を原振とする低速側のタイマーとなっているようである。
つまりledcで沢山のチャネルを使用する時は、上記事柄に気を付けて使う必要がある。
※低速側タイマーの場合、最大のPWM周波数は312KHz(8bit解像度)くらい?
※高速側タイマーの場合、最大のPWM周波数は312KHz(8bit解像度)くらい?
※え!う~~~~ん、高速は判る、80MHzを256で割れば312KHzだしい。まるでウドンのキツネをつまんでいる様な、、、
※結局グループ0側も、グループ1側も、解像度を2bitにすると20MHzの波形を出力できるのう!なんだったのだろう???
※20MHzにすると、IO18とIO21が出力しない。
さて、件のLOWが出ない件であるが、Duty=0とした時の波形が以下である。
LOWフラット、、、
試しにDuty=100とした時の波形は以下である。
3.3Vフラットに見えるが、立下りのヒゲが出ている、、、
なので以下の様なコードを書いてお確かめ。
ESP32_LEDC_TEST.ino
#include "led.h" #define LED_CH0_PIN 32 #define LED_CH1_PIN 33 #define LED_CH2_PIN 25 #define LED_CH3_PIN 26 #define LED_CH4_PIN 27 #define LED_CH5_PIN 14 #define LED_CH6_PIN 13 #define LED_CH7_PIN 15 #define LED_CH8_PIN 4 #define LED_CH9_PIN 16 #define LED_CH10_PIN 17 #define LED_CH11_PIN 5 #define LED_CH12_PIN 18 #define LED_CH13_PIN 19 #define LED_CH14_PIN 21 #define LED_CH15_PIN 22 #define LED_CH0_FRQ 1000.0 /* hz チャネル0とチャネル1は同一タイマーの為、後から設定した方の周波数になるはず */ #define LED_CH1_FRQ 2000.0 /* hz チャネル0とチャネル1は同一タイマーの為、後から設定した方の周波数になるはず */ #define LED_CH2_FRQ 3000.0 /* hz チャネル2とチャネル3は同一タイマーの為、後から設定した方の周波数になるはず */ #define LED_CH3_FRQ 4000.0 /* hz チャネル2とチャネル3は同一タイマーの為、後から設定した方の周波数になるはず */ #define LED_CH4_FRQ 5000.0 /* hz チャネル4とチャネル5は同一タイマーの為、後から設定した方の周波数になるはず */ #define LED_CH5_FRQ 6000.0 /* hz チャネル4とチャネル5は同一タイマーの為、後から設定した方の周波数になるはず */ #define LED_CH6_FRQ 7000.0 /* hz チャネル6とチャネル7は同一タイマーの為、後から設定した方の周波数になるはず */ #define LED_CH7_FRQ 8000.0 /* hz チャネル6とチャネル7は同一タイマーの為、後から設定した方の周波数になるはず */ #define LED_CH8_FRQ 9000.0 /* hz チャネル8とチャネル9は同一タイマーの為、後から設定した方の周波数になるはず */ #define LED_CH9_FRQ 10000.0 /* hz チャネル8とチャネル9は同一タイマーの為、後から設定した方の周波数になるはず */ #define LED_CH10_FRQ 20000.0 /* hz チャネル10とチャネル11は同一タイマーの為、後から設定した方の周波数になるはず */ #define LED_CH11_FRQ 30000.0 /* hz チャネル10とチャネル11は同一タイマーの為、後から設定した方の周波数になるはず */ #define LED_CH12_FRQ 40000.0 /* hz チャネル12とチャネル13は同一タイマーの為、後から設定した方の周波数になるはず */ #define LED_CH13_FRQ 50000.0 /* hz チャネル12とチャネル13は同一タイマーの為、後から設定した方の周波数になるはず */ #define LED_CH14_FRQ 60000.0 /* hz チャネル14とチャネル15は同一タイマーの為、後から設定した方の周波数になるはず */ #define LED_CH15_FRQ 70000.0 /* hz チャネル14とチャネル15は同一タイマーの為、後から設定した方の周波数になるはず */ #define LED_CH0_RES (8) /* resolution */ #define LED_CH1_RES (8) /* resolution */ #define LED_CH2_RES (8) /* resolution */ #define LED_CH3_RES (8) /* resolution */ #define LED_CH4_RES (8) /* resolution */ #define LED_CH5_RES (8) /* resolution */ #define LED_CH6_RES (8) /* resolution */ #define LED_CH7_RES (8) /* resolution */ #define LED_CH8_RES (8) /* resolution */ #define LED_CH9_RES (8) /* resolution */ #define LED_CH10_RES (8) /* resolution */ #define LED_CH11_RES (8) /* resolution */ #define LED_CH12_RES (8) /* resolution */ #define LED_CH13_RES (8) /* resolution */ #define LED_CH14_RES (8) /* resolution */ #define LED_CH15_RES (8) /* resolution */ #define DUTY( duty,res ) map( duty,0,100,0,(1 << res) - 1 ) led led_0( LED_CH0_PIN, 0 ); led led_1( LED_CH1_PIN, 1 ); led led_2( LED_CH2_PIN, 2 ); led led_3( LED_CH3_PIN, 3 ); led led_4( LED_CH4_PIN, 4 ); led led_5( LED_CH5_PIN, 5 ); led led_6( LED_CH6_PIN, 6 ); led led_7( LED_CH7_PIN, 7 ); led led_8( LED_CH8_PIN, 8 ); led led_9( LED_CH9_PIN, 9 ); led led_10( LED_CH10_PIN, 10 ); led led_11( LED_CH11_PIN, 11 ); led led_12( LED_CH12_PIN, 12 ); led led_13( LED_CH13_PIN, 13 ); led led_14( LED_CH14_PIN, 14 ); led led_15( LED_CH15_PIN, 15 ); void setup() { /* led 0 */ led_0.begin( LED_CH0_FRQ, LED_CH0_RES ); led_0.write( DUTY( 50,LED_CH0_RES) ); /* led 1 */ led_1.begin( LED_CH1_FRQ, LED_CH1_RES ); led_1.write( DUTY( 50,LED_CH1_RES) ); /* led 2 */ led_2.begin( LED_CH2_FRQ, LED_CH2_RES ); led_2.write( DUTY( 50,LED_CH2_RES) ); /* led 3 */ led_3.begin( LED_CH3_FRQ, LED_CH3_RES ); led_3.write( DUTY( 50,LED_CH3_RES) ); /* led 4 */ led_4.begin( LED_CH4_FRQ, LED_CH4_RES ); led_4.write( DUTY( 50,LED_CH4_RES) ); /* led 5 */ led_5.begin( LED_CH5_FRQ, LED_CH5_RES ); led_5.write( DUTY( 50,LED_CH5_RES) ); /* led 6 */ led_6.begin( LED_CH6_FRQ, LED_CH6_RES ); led_6.write( DUTY( 50,LED_CH6_RES) ); /* led 7 */ led_7.begin( LED_CH7_FRQ, LED_CH7_RES ); led_7.write( DUTY( 50,LED_CH7_RES) ); /* led 8 */ led_8.begin( LED_CH8_FRQ, LED_CH8_RES ); led_8.write( DUTY( 50,LED_CH8_RES) ); // led_8.write( 0 ); // led_8.write( 255 ); /* led 9 */ led_9.begin( LED_CH9_FRQ, LED_CH9_RES ); led_9.write( DUTY( 50,LED_CH9_RES) ); /* led 10 */ led_10.begin( LED_CH10_FRQ, LED_CH10_RES ); led_10.write( DUTY( 50,LED_CH10_RES) ); /* led 11 */ led_11.begin( LED_CH11_FRQ, LED_CH11_RES ); led_11.write( DUTY( 50,LED_CH11_RES) ); /* led 12 */ led_12.begin( LED_CH12_FRQ, LED_CH12_RES ); led_12.write( DUTY( 50,LED_CH12_RES) ); /* led 13 */ led_13.begin( LED_CH13_FRQ, LED_CH13_RES ); led_13.write( DUTY( 50,LED_CH13_RES) ); /* led 14 */ led_14.begin( LED_CH14_FRQ, LED_CH14_RES ); led_14.write( DUTY( 50,LED_CH14_RES) ); /* led 15 */ led_15.begin( LED_CH15_FRQ, LED_CH15_RES ); led_15.write( DUTY( 50,LED_CH15_RES) ); } void loop() { }
led.h
/****************************************************************************/ /* led header */ /* Copyright (C) 2018 hamayan All Rights Reserved. */ /****************************************************************************/ #ifndef LED_h #define LED_h #include <Arduino.h> #include <esp32-hal-ledc.h> extern "C" { } class led { private : uint8_t ledPin; uint8_t ledChannel; public : led( uint8_t pin, uint8_t channel ); ~led(); double begin( double freq, uint8_t resolution_bits ); void write( uint32_t duty ); uint32_t read(); double tone( double freq ); double note( note_t note, uint8_t octave ); }; #endif /* LED_h */ /****************************************************************************/ /* Copyright (C) 2018- by hamayan */ /****************************************************************************/
led.c
/****************************************************************************/ /* led source */ /* Copyright (C) 2018 hamayan All Rights Reserved. */ /****************************************************************************/ #include "led.h" /*************************************************************************/ /* constructor,destructor */ /*************************************************************************/ led::led( uint8_t pin, uint8_t channel ) { ledPin = pin; ledChannel = channel; ledcAttachPin( pin, channel ); } led::~led() { ledcDetachPin( ledPin ); } /*************************************************************************/ /* begin */ /*************************************************************************/ double led::begin( double freq, uint8_t resolution_bits ) { return ledcSetup( ledChannel, freq, resolution_bits ); } /*************************************************************************/ /* write (duty) */ /*************************************************************************/ void led::write( uint32_t duty ) { ledcWrite( ledChannel, duty ); } /*************************************************************************/ /* read (duty) */ /*************************************************************************/ uint32_t led::read() { return ledcRead( ledChannel ); } /*************************************************************************/ /* tone */ /*************************************************************************/ double led::tone( double freq ) { return ledcWriteTone( ledChannel, freq ); } /*************************************************************************/ /* note */ /*************************************************************************/ double led::note( note_t note, uint8_t octave ) { return ledcWriteNote( ledChannel, note, octave ); } /****************************************************************************/ /* Copyright (C) 2018- by hamayan */ /****************************************************************************/
チャネル0のみ1000HzでDuty=50%の波形を出力してみると以下の波形となった。
次に全16チャネルを出力させてみた。その時のチャネル0の波形が以下である。
お判り頂けたであろうか?PWM周波数が変わってしまっている。
以下はesp32_hal_ledc.cの一部抜粋である。
/* * LEDC Chan to Group/Channel/Timer Mapping ** ledc: 0 => Group: 0, Channel: 0, Timer: 0 ** ledc: 1 => Group: 0, Channel: 1, Timer: 0 ** ledc: 2 => Group: 0, Channel: 2, Timer: 1 ** ledc: 3 => Group: 0, Channel: 3, Timer: 1 ** ledc: 4 => Group: 0, Channel: 4, Timer: 2 ** ledc: 5 => Group: 0, Channel: 5, Timer: 2 ** ledc: 6 => Group: 0, Channel: 6, Timer: 3 ** ledc: 7 => Group: 0, Channel: 7, Timer: 3 ** ledc: 8 => Group: 1, Channel: 0, Timer: 0 ** ledc: 9 => Group: 1, Channel: 1, Timer: 0 ** ledc: 10 => Group: 1, Channel: 2, Timer: 1 ** ledc: 11 => Group: 1, Channel: 3, Timer: 1 ** ledc: 12 => Group: 1, Channel: 4, Timer: 2 ** ledc: 13 => Group: 1, Channel: 5, Timer: 2 ** ledc: 14 => Group: 1, Channel: 6, Timer: 3 ** ledc: 15 => Group: 1, Channel: 7, Timer: 3 */
チャネル0とチャネル1は同一タイマーとなっている、、、ようするにチャネル0とチャネル1間では、後から設定した方が有効となってしまう。そりゃそうだ、、、
またチャネル0からチャネル7までと、チャネル8からチャネル15までで異なるグループとなっている。これはグループ0が80MHzを原振とする高速側のタイマー、グループ1が1MHz?を原振とする低速側のタイマーとなっているようである。
つまりledcで沢山のチャネルを使用する時は、上記事柄に気を付けて使う必要がある。
※低速側タイマーの場合、最大のPWM周波数は312KHz(8bit解像度)くらい?
※高速側タイマーの場合、最大のPWM周波数は312KHz(8bit解像度)くらい?
※え!う~~~~ん、高速は判る、80MHzを256で割れば312KHzだしい。まるでウドンのキツネをつまんでいる様な、、、
※結局グループ0側も、グループ1側も、解像度を2bitにすると20MHzの波形を出力できるのう!なんだったのだろう???
※20MHzにすると、IO18とIO21が出力しない。
さて、件のLOWが出ない件であるが、Duty=0とした時の波形が以下である。
LOWフラット、、、
試しにDuty=100とした時の波形は以下である。
3.3Vフラットに見えるが、立下りのヒゲが出ている、、、
ESP32でアラームハンドラーが動いたり、動かなかったり、チップリビジョン? [ESP32]
経緯はここを見てね。
https://www.facebook.com/groups/927623023964478/permalink/1966158430110927/?comment_id=1973470699379700¬if_id=1539774777726286¬if_t=group_comment_follow
ESP32のチップリビジョンでアラームハンドラが動いたり動かなかったりする事は確認。
こまったねぇ、、、
https://www.facebook.com/groups/927623023964478/permalink/1966158430110927/?comment_id=1973470699379700¬if_id=1539774777726286¬if_t=group_comment_follow
ESP32のチップリビジョンでアラームハンドラが動いたり動かなかったりする事は確認。
こまったねぇ、、、