こんにちは、shotaです。
前回の記事ではGPIOとADCを使って物体検出センサを動かしました。
1 msecのdelayができていないという問題がありました。
今回はFreeRTOSの動作周波数を変更して1 msec delayを実現します。
ブロクで書いたサンプルコードはGitHubに公開しています。
https://github.com/ShotaAk/especial/tree/master/examples
ESP-IDFで1 msec delay を作る方法
今回は先にやり方を書いて、その後1 msec delayが正しく動いたかどうかをオシロスコープで確認します。
答え:sdkconfigを編集する
ESP-IDFのプロジェクトでmake menuconfigを実行するとsdkconfigという設定ファイルが生成されます。
このファイルのCONFIG_FREERTOS_HZを100から1000に書き換えると1 msec delayが実現します。
--- 省略 --- # FreeRTOS # CONFIG_FREERTOS_UNICORE= CONFIG_FREERTOS_NO_AFFINITY=0x7FFFFFFF CONFIG_FREERTOS_CORETIMER_0=y CONFIG_FREERTOS_CORETIMER_1= CONFIG_FREERTOS_HZ=1000 ← ここを100から1000に変更する CONFIG_FREERTOS_ASSERT_ON_UNTESTED_FUNCTION=y --- 省略 ---
より簡単なsdkconfigの編集方法
テキストエディタでsdkconfigを編集するのは面倒ですよね。
設定を書き間違える可能性もあります。
ここでは、make menuconfig を使いましょう。
# プロジェクトディレクトリに移動 $ cd ~/esp/especial/examples/3_object_detector # menuconfig実行 $ make menuconfig
make menuconfigコマンドを実行すると設定画面が表示されます。
Component config -> FreeRTOS -> Tick rate (Hz) に進み 1000 を入力します。
Save して終了すれば、sdkconfigの編集完了です。
もっと簡単なsdkconfigの編集方法
プロジェクトを作るたびにmenuconfigでFreeRTOSの設定をするのは面倒ですよね。
こんなときは、sdkconfig.defaultsファイルを作成しましょう。
sdkconfig.defaultsは、make menuconfigでsdkconfigファイルを生成するときに読み込まれます。
sdkconfig.defaultsに書いた設定項目が、sdkconfigファイルに上書きされるのです。
詳細はこちらに書かれています。
Custom sdkconfig defaults | ESP-IDF Programming Guide
例えば、Especialのプロジェクトにあるsdkconfig.defaultsはつぎのように書かれています。
CONFIG_PARTITION_TABLE_CUSTOM=y CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions_example.csv" CONFIG_PARTITION_TABLE_CUSTOM_APP_BIN_OFFSET=0x10000 CONFIG_PARTITION_TABLE_FILENAME="partitions_example.csv" CONFIG_APP_OFFSET=0x10000 CONFIG_ESP32_DEFAULT_CPU_FREQ_240=y CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ=240 CONFIG_FREERTOS_HZ=1000
パーティションテーブルや、CPU動作周波数、FreeRTOS動作周波数の設定値を書いています。
それでは、前回の物体検出センサのプロジェクトにsdkconfig.defaultsファイルを追加しましょう。
追加したファイルがこちらです。
CONFIG_FREERTOS_HZ=1000
本当にsdkconfig.defaultsが機能するか心配な人は、次の手順で試してみてください。
# sdkconfigファイルを削除 $ rm sdkconfig # menuconfig実行(何も変更せずに終了する) $ make menuconfig # 生成されたsdkconfigファイルの確認 $ cat sdkconfig | grep CONFIG_FREERTOS_HZ
1 msec delayが正しく動いているか確認
実際に1 msec delayが動作するのか、前回のプログラムとオシロスコープを使って確認します。
プログラムと回路図についてはこちらを参照してください。
ESP32マウスPart.32 GPIOとADCで物体検出センサを動かす
main.cには次のように書かれています。
while (1) { --- 省略 --- // LED ON gpio_set_level(GPIO_L_FR, 1); // 壁に反射するまで待つ vTaskDelay(1 / portTICK_RATE_MS); // ADC adc_readings[AN_IR_L] = adc1_get_raw((adc1_channel_t)CHANNELS[AN_IR_L]); adc_readings[AN_IR_FR] = adc1_get_raw((adc1_channel_t)CHANNELS[AN_IR_FR]); // LED OFF gpio_set_level(GPIO_L_FR, 0); --- 省略 --- vTaskDelay(100 / portTICK_RATE_MS); }
赤外線LEDを点灯した後、vTaskDelayで1 msec待機し、赤外線LEDを消灯しています。
whileの最後にはvTaskDelayで100 msec待機しています。
それでは、GPIO_L_FRの接続先のFETのゲート波形を見てみましょう。
まずは、波形の全体像から。
約 100 msec毎にパルスが出ていることがわかります。
拡大してみましょう。
1 msec間信号が出ていることがわかります。
1 msec delayが正しく動いているようですね。
そもそもvTaskDelayとは何なのか
ここまで何も説明なしに使用しているvTaskDelayですが、そもそもこの関数は何なのでしょう?
ESP-IDF公式マニュアルで調べてみます。
Delay a task for a given number of ticks.
The actual time that the task remains blocked depends on the tick rate. The constant portTICK_PERIOD_MS can be used to calculate real time from the tick rate – with the resolution of one tick period.
ふむふむ・・・tickやらblockやら知らない単語が出てきましたね。。。
vTaskDelayは、何msec間停止する、のではなく、何tick間自身のタスクをブロック状態にする、という関数です。
今回、FreeRTOSの動作周波数を1000Hzに設定したので、1 msec毎にtick割り込みが発生します。
そのため、vTaskDelay(1 / portTICK_RATE_MS)は vTaskDelay(1)となり、tick 1回分のdelay(1 msec)になります。
デフォルトでは、FreeRTOSの動作周波数が100Hzなので、10 msec毎にtick割り込みが発生します。
この場合、vTaskDelayで1 msecのdelayを発生させることはできません。
・・・
途端に話がややこしくなりましたね。
FreeRTOSに慣れている人は、この物体検出センサのプログラムがそのうち期待通りに動かなくなることを見抜いているかもしれません。
FreeRTOSについては、もっと先のブログ記事に書きます。
まずは、Especialの周辺機能(モータやエンコーダ)について記事を書き続けます。
次回の記事
次はモータを回します。PWM機能の登場です。