2024.2.13 Coskx Lab
Xiao ESP32S3でPWM信号を発生します。
(1)PWM信号
PWM(Pulse Width Modulation)信号というのは,短いパルス信号を一定周期で発し,モータなどのONOFF制御を高速に行うためのものです。
しかもONの時間とOFFの時間の比率を自由に変更できるようになっています。
参考 PWM波形の例 (https://www.mbtechworks.com/projects/raspberry-pi-pwm.html)
パルス周期はPWM周期(PWM period)とも呼ばれ,その逆数はPWM周波数(PWM frequency)と呼ばれます。
また「パルス幅/パルス周期」の値はデューティー比(duty ratio, duty cycle)と呼ばれます。
(2)ESP32S3がPWM信号を発生する仕組み
PWM信号の生成ではESP32S3の指定したピンに対して,プログラムで手工業的にHとLを交互に出力する作業をしているわけではありません。
EPS32にはPWM発生回路(PWMモジュール)があります。
プログラムはこのPWM発生回路(PWMモジュール)に対してPWM周期やパルス幅を与えて,PWM波形を発生します。
PWMモジュールがPWM波形を発生しただけではまだ外部にPWM信号は見えません。
EPS32は多くのGPIOピン(GPIOは,General-purpose input/output,汎用入出力)を持っています。
GPIOピンは入力に使われるのか出力に使われるのかさえ決まっていない多用途ピンです。
選定したGPIOピンを出力用途に設定し,PWMモジュールが生成しているPWM信号をそのピンから出力するように設定します。
こうして初めてあるピンからPWM信号が出力されるようになります。
(3)プログラムが行うこと(詳細)
(4)Arduinoライブラリが更新され,使用関数が変更
Arduino ESP32 coreのバージョンが2.Xから3.0になり,
ledcSetup(), ledcAttachPin() は廃止され,ledcAttachChannel()を使うことになりました。
https://github.com/espressif/arduino-esp32/blob/master/docs/en/migration_guides/2.x_to_3.0.rst#id4
PWM波形を生成しますが,生成するデューティー比は離散的で
0/256, 1/256, 10/256, 64/256, 128/256, 192/256, 255/256, 256/256, 257/256
とします。(257/256は動作チェックのためです)
PCからのシリアル通信で,LFを与えるたびにデューティー比を増加させ,最大になったら元に戻ります。
その他の設定値は次の通りです。
・PWM生成に使用するビット数: 8bit
・PWM周波数:2000Hz
・使用するPWMモジュール(PWMチャンネル):2
・PWM出力に使用するPINの名前:D0
PWMに関連する関数名はledc○○○○○になっています。
最初に開発されたときに,LEDの明るさ制御に使われたようで,LED_Controlの名残と思われます。
PWMの動作テスト用プログラム本体
PWM信号の出力は「D0」です。
この信号をオシロスコープで観察するために,次のように配線しました。
PWM信号の生成は内部のカウンタが用いられています。そのためカウンタを何ビット使うかを設定する必要があります。
カウンタのビット数が決まると,最大PWM周波数・最小PWM周波数が決まり,デューティー指令値(PWM指令値)の範囲が定まります。
デューティー指令値(PWM指令値)を指示すると,デューティー比が決まります。
1)PWMに使用するビット数 n = 1~16 [bit]
2)PWM周波数に設定できる最大周波数,最小周波数は, n とソースクロックに依存します。
ソースクロックが80MHzの場合
最大PWM周波数 MaxFrequency = 80000000.0 ÷ 2n[Hz]
最小PWM周波数 MinFrequency = 80000000.0 ÷ 2n+16[Hz]
例
bit数 n | resolution 2n | MaxFrequency[Hz] | MinFrequency[Hz] |
16 | 65536 | 1220.70 | 0.018626451 |
12 | 4096 | 19531.25 | 0.298023224 |
8 | 256 | 312500 | 4.768371582 |
4 | 16 | 5000000 | 76.29394531 |
1 | 2 | 40000000 | 610.3515625 |
PWM発生に使用するビット数を8に設定してPWM値を0から1,2,..254,255,256,257までテストしました。
(8ビットでは0から255までしか表せないはずですが,257まで試しました。)
わかったこと
PWM値 | 想定デューティ比(パルス幅) | 実測デューティ比(パルス幅) |
0 | 0/256 (0%) | 0 (0%) |
1 | 1/256 (0.4%) | 約2μsec (0.4%) |
2 | 2/256 (0.8%) | 約4μsec (0.8%) |
10 | 10/256 (4.0%) | 約20μsec (4.0%) |
254 | 254/256 (99.2%) | 約496μsec (99.2%) |
255 | 255/256 (99.6%) | 常にH (100%) ←変だ |
256 | 256/256 (100%) | 常にH (100%) |
257 | 257/256 (100.4%) | 約2μsec (0.4%) |
PWM値で示されるデューティ比パルスが生成されました
PWM値が256のときに100%のHが主力されました。
ただし,PWM値が255のときにも100%のHが主力されました。
PWM値が255のときの異常な動作は,ライブラリのプログラムにより引き起こされていることがわかりました。
C:\Users\[ユーザ名]\AppData\Local\Arduino15\packages\esp32\hardware\esp32\2.0.11\cores\esp32\esp32-hal-ledc.c
に次のような記述があります。
256/256のデューティ比を与えるとPWM発生器が常時Hを出力することになっていることはわかっています。
なぜかmax_dutyを255に設定していて,dutyがmax_dutyに等しいとき,すなわちduty=255のときにduty = max_duty + 1 (=256) にしています。
このような作業は不要です。
このファイルのオリジナルは別名で確保して,問題部分をカットし,次のようにして,PWM値が255のときに99.6%のHが主力されるようになりました。
PWM値 | 想定デューティ比(パルス幅) | 実測デューティ比(パルス幅) |
254 | 254/256 (99.2%) | 約496μsec (99.2%) |
255 | 255/256 (99.6%) | 約498μsec (99.6%)←正常 |
256 | 256/256 (100%) | 常にH (100%) |
この部分は不思議ですが,多くのArduinoマイコンのPWM生成ハードウエアに対応するようになっているため,多数派に従った造りになっているのかもしれません。
ただし,ESP32-WROOM-32Eにおいても,この修正は有効であったため,使用CPUの動作を見ながら対応するのがよさそうです。
以下は実際の様子です。
1)
PWM_Frequency = 2000.0Hz,
PWM_Value = 128, PWM ratio=50%
2V/div 1ms/div
設定どおり,PWM周波数2000Hz
PWM周期0.5msec,500μsec
dutyRatio50%で動作している
2)
PWM_Frequency = 2000.0Hz,
PWM_Value = 1, PWM ratio=1/256
1μs/div
設定どおり,PWM周波数2000Hz
PWM周期0.5msec,500μsec
dutyRatio1/256なので
パルス幅は500μsec/256=1.953125μsecのはず
実測値は1.94μsec(オシロの自動計測)
3)
PWM_Frequency = 2000.0Hz,
PWM_Value = 0, PWM ratio=0/256
すべてL信号
4)
PWM_Frequency = 2000.0Hz,
PWM_Value = 1, PWM ratio=1/256
1/256幅の短いパルスが見える
5)
PWM_Frequency = 2000.0Hz,
PWM_Value = 10, PWM ratio=10/256
10/256幅の短いパルスが見える(見やすい)
6)
PWM_Frequency = 2000.0Hz,
PWM_Value = 64, PWM ratio=64/256=1/4
25%幅のパルスが見える
7)
PWM_Frequency = 2000.0Hz,
PWM_Value = 128, PWM ratio=128/256=1/2
50%幅のパルスが見える
8)
PWM_Frequency = 2000.0Hz,
PWM_Value = 192, PWM ratio=192/256=3/4
75%幅のパルスが見える
9)
PWM_Frequency = 2000.0Hz,
PWM_Value = 255, PWM ratio=255/256
255/256幅のパルスが見える
(1/256だけ短くお休み)
10)
PWM_Frequency = 2000.0Hz,
PWM_Value = 256, PWM ratio=256/256
全期間にわたってH信号が見える
通常デジタル機器は8bitを扱うなら0から255 (28-1)までしか対応できないのに,
親切な設計となっています
ピン割り当て,PWMモジュール(PWMチャンネル)割り当てを行いPWM信号を生成しました。
ライブラリファイルを一部手直しして,意図したデューティー比のPWM波形を生成することができました。
信号観察結果も予想通りでした。