2023/1/4 文章修正と内容訂正しました。
2023/4/12 ESP-IDFバージョンについての記述を追加しました。
公式版ESP-IDFのAPIはV4.4からV5へのバージョンアップで大幅に仕様が変わっていました。
PlatformIO版ESP-IDFはV6が公式版V5に相当します。これがややこしく、私も混同していましたので、以下のPCNTについての内容はPlatformIO版V5では公式版V5の記述ができない、という至極当然のことだったわけで、訂正いたします。
PCNTも含まれ、記述や関数名が変わっています。参考はここ
ところが、PlatformIOでESP32-S3をESP-IDF V5.1.1で開発してみると、新しい仕様のPCNTが使えない。無理やり「pulse_cnt.h」「pulse_cnt.c」を組み込んでも当然ながらframeworkにhalのドライバが存在しないのでリンカが通らない。なにより小手先の対策はESP-IDFのバージョンを変えるとフレームワークも一新されるので得策ではありません。
今回はレガシィ記述でPCNTを使うことにしました。その覚書です。
古いPrograminng Manualを探して導入
公式ホームページからのリンクはたどれませんが、旧版のマニュアルページが残っていました。V3.3.6のPrograminng Manualを参考にレガシーPCNTを導入します。
2023/1/4 訂正
よくよく確認したら、公式ページからたどれるV4.4.3のページのPCNTはレガシー記述のマニュアルでした。現在このページには「Download PDF」のリンクが存在するので、できるうちにPDFマニュアルもDLしておきました。PCNT以外のペリフェラルもこういった事例が存在するかもしれませんので、保険です。
ここからexsampleもたどれます。
ポートからパルスを入力して、シリアルモニターにRPM表示
以下は、レガシー記述でPCNTをセットするプログラムです。
ポート41からのパルスを1秒ごとにシリアルモニターにrpm表示で出力するだけの動作プログラムの抜粋です。
#include <stdio.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "driver/pcnt.h"
void init_PCNT(void) {
pcnt_config = {
.pulse_gpio_num = (gpio_num_t)41, // port41
.ctrl_gpio_num = -1, // 制御信号使わない
.channel = PCNT_CHANNEL_0, // ch0
.unit = unit, // unit0
.pos_mode = PCNT_COUNT_INC, // 立上りエッジでアップ
.neg_mode = PCNT_COUNT_DIS, // 立下りエッジは機能しない
.lctrl_mode = PCNT_MODE_KEEP, // 制御信号L設定変更なし
.hctrl_mode = PCNT_MODE_KEEP, // 制御信号H設定変更なし
.counter_h_lim = 3000,
.counter_l_lim = 0,
};
pcnt_unit_config(&pcnt_config);
pcnt_set_filter_value(unit, 100);
pcnt_filter_enable(unit);
pcnt_counter_pause(unit);
pcnt_counter_clear(unit);
pcnt_counter_resume(unit);
}
void pcntTestTask(void *pvParameters) {
int16_t cntval;
init_PCNT();
while (1) {
pcnt_get_counter_value(unit, &cntval);
pcnt_counter_clear(unit);
printf("%d\r\n", cntval*60/32);
vTaskDelay(1000);
}
}
抜粋なので抜けてますが、ポート41は入力に設定しておきます。メインで「pcntTestTask()」を起動しています。あとRTOSのTickは1000Hzにしてあります。表示を32で割っているのは、たまたま確認したベンチが一回転32パルスだっただけです。
コンパイラは難なく通り、実機で動作OKでした。SGから2,133.333Hzを入力し、vTaskDelayで1秒を単純に区切ってみただけですが表示は4,000(タイミングによっては3999)rpmと正確に出ました。