SNSへはこちら

ESP32で遊んでみる(6) - ADC・DAC

どんどん行きましょう。お次はアナログ関係。

結論から言うと、かなり簡単です。まあ SDK 使ってるんですからそりゃそうだけど。

ADC

アナログ値を読み取るやつです。若干面倒ですが...

ソースコードと説明

ご覧の通り。スッキリと書けます。なんとなく FreeRTOS 使ってみました。

#include <stdio.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "driver/gpio.h"
#include "driver/adc.h"
#include "sdkconfig.h"

void vAdc(void *pvParameters) {
    adc_gpio_init(ADC_UNIT_1, ADC_CHANNEL_0);
    adc1_config_width(ADC_WIDTH_BIT_12);
    adc1_config_channel_atten(ADC1_CHANNEL_0, ADC_ATTEN_DB_11);

    while(1) {
        printf("%d\n", adc1_get_raw(ADC1_CHANNEL_0));
        vTaskDelay(1000 / portTICK_PERIOD_MS);
    }
}

void app_main(void) {
    xTaskCreatePinnedToCore(vAdc, "ADC", 1024 * 2, NULL, 1, NULL, 1);
}

説明することは Attenuation と入力電圧範囲でしょうか。ドキュメンテーションによると、次のことが書かれています。

  • 0 dB attenuation (ADC_ATTEN_DB_0) gives full-scale voltage 1.1 V
  • 2.5 dB attenuation (ADC_ATTEN_DB_2_5) gives full-scale voltage 1.5 V
  • 6 dB attenuation (ADC_ATTEN_DB_6) gives full-scale voltage 2.2 V
  • 11 dB attenuation (ADC_ATTEN_DB_11) gives full-scale voltage 3.9 V (see note below)

つまり、上で書いた ADC_ATTEN_DB_11 が上に対応しているわけです。この場合は入力電圧が 3.9V まで変換されるというわけ。だから電圧値として換算するなら、今回は 3.9 を乗じればいいです。
更に補足として、ドキュメンテーションには推奨電圧範囲(suggested range) が書かれていました。特のこの範囲の特性が良いようです(線形性という点で?)。使用するアプリケーションに応じてここらへんは調節しましょう。

    +----------+------------+--------------------------+
    |   SoC    | attenuation|   suggested range (mV)   |
    +==========+============+==========================+
    |          |  0         |     100 ~ 950            |
    |          +------------+--------------------------+
    |          |  2.5       |     100 ~ 1250           |
    |   ESP32  +------------+--------------------------+
    |          |  6         |     150 ~ 1750           |
    |          +------------+--------------------------+
    |          |  11        |     150 ~ 2450           |
    +----------+------------+--------------------------+
    |          |  0         |     100 ~ 800            |
    |          +------------+--------------------------+
    |          |  2.5       |     100 ~ 1100           |
    | ESP32-S2 +------------+--------------------------+
    |          |  6         |     150 ~ 1350           |
    |          +------------+--------------------------+
    |          |  11        |     150 ~ 2600           |
    +----------+------------+--------------------------+

DAC

お次は DAC です。

LEDボヤァのコード

地味に面白い cw の機能があります。まずは通常の LED ボヤァをどうぞ。説明することはマジでない。

#include <stdio.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "driver/gpio.h"
#include "driver/dac.h"
#include "sdkconfig.h"

void vDacIncr(void *pvParameters) {
    dac_output_enable(DAC_CHANNEL_1);

    uint8_t voltage = 0;
    while(1) {
        dac_output_voltage(DAC_CHANNEL_1, voltage += 16);
        vTaskDelay(10);
    }
}

void app_main(void) {
    xTaskCreatePinnedToCore(vDacIncr, "DAC with Increment", 1024 * 2, NULL, 1, NULL, 1);
}

CWジェネレータ

この機能は cos 波形を自動的に生成する機能です。関係ないけど、無線免許を持っている自分からしたら CW ってモールス信号だと思いましたね。

#include <stdio.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "driver/gpio.h"
#include "driver/dac.h"
#include "sdkconfig.h"

void vDacCwGen(void *pvParameters) {
    dac_cw_config_t config = {
        .en_ch = DAC_CHANNEL_1,
        .scale = DAC_CW_SCALE_1,
        .phase = DAC_CW_PHASE_0,
        .freq = 130,
        /* .offset = 0 */
        .offset = 1
    };
    dac_output_enable(DAC_CHANNEL_1);
    dac_cw_generator_config(&config);
    dac_cw_generator_enable();

    while(1) {
        vTaskDelay(1);
    }
}

void app_main(void) {
    xTaskCreatePinnedToCore(vDacCwGen, "DAC with CW Generator", 1024 * 2, NULL, 1, NULL, 1);
}

地味な注意点は offset です。別に DC オフセットは必要じゃなかったので 0 でいいのかなあと思いましたが、なんかこれじゃあダメでした。良くわからん(ひょっとして ESP-IDF のバグ?)。
一度有効化したら何も操作は要りません。