nRF SAADC
ADCの基礎をやってみる。
nRF52840のADC
単なるADCといわずSAADCと呼ぶらしい。
https://infocenter.nordicsemi.com/pdf/nRF52840_PS_v1.1.pdf
Analogピンとして使えるピンはどれでもという訳ではない。
576ページにあるがAIN7 Analog inputと書かれているピンで
AIN0 P0.02
AIN1 P0.03
AIN2 P0.04
AIN3 P0.05
AIN4 P0.28
AIN5
P0.29
AIN6 P0.30
AIN7 P0.31
コーディング
UART、NRF_LOGが使えるTemplateからスタート。コピーをとってという所は毎回同じ。
インクルードファイル
//To use SAADC
#include "nrf_drv_saadc.h"
AD変換チャンネルの設定
今回はメインの中に、Templateを使っていると、NRF_LOGのイニシャライズ等はした後に、
ret_code_t err_code;
//define config struct and pin assign
nrf_saadc_channel_config_t channel_config =
{
.resistor_p = NRF_SAADC_RESISTOR_DISABLED, ///< Resistor value on positive input.
.resistor_n = NRF_SAADC_RESISTOR_DISABLED, ///< Resistor value on negative input.
.gain = NRF_SAADC_GAIN1_6, ///< Gain control value.
.reference = NRF_SAADC_REFERENCE_INTERNAL, ///< Reference control value.
.acq_time = NRF_SAADC_ACQTIME_10US, ///< Acquisition time.
.mode = NRF_SAADC_MODE_SINGLE_ENDED, ///< SAADC mode. Single-ended or differential.
.burst = NRF_SAADC_BURST_DISABLED, ///< Burst mode configuration.
.pin_p = NRF_SAADC_INPUT_AIN0, ///< Input positive pin selection.
.pin_n = NRF_SAADC_INPUT_DISABLED ///< Input negative pin selection.
};
nrf_saadc_channel_config_t という構造体が定義されているので、その要素を記述して設定をする。各設定値の中身は、https://infocenter.nordicsemi.com/index.jsp?topic=%2Fcom.nordic.infocenter.nrf52832.ps.v1.1%2Fsaadc.htmlなどを参照。簡単に以下は説明
resistor_p, resistor_n
ADC は以下のようい正負入力用に内部抵抗をもっていてその設定をする。普通にシングルエンドで測定するだけなら、NRF_SAADC_RESISTOR_DISABLED を選択.他の使い方は・・・
Enumerator | |
---|---|
NRF_SAADC_RESISTOR_DISABLED | Bypass resistor ladder. |
NRF_SAADC_RESISTOR_PULLDOWN | Pull-down to GND. |
NRF_SAADC_RESISTOR_PULLUP | Pull-up to VDD. |
NRF_SAADC_RESISTOR_VDD1_2 | Set input at VDD/2. |
.gainとreference
リファレンス電圧の設定。内部の0.6かVDDの1/4の電圧にするか?
Enumerator | |
---|---|
NRF_SAADC_REFERENCE_INTERNAL | Internal reference (0.6 V). |
NRF_SAADC_REFERENCE_VDD4 | VDD/4 as reference. |
Input range = (+- 0.6 V or +-VDD/4)/Gain
で示されて、ゲインで割る事になる
仮に internal referenceで single ended input (ネガティブ入力はGNDに接続),そしてゲインを1/6に設定すると、入力レンジは、
Input range = (0.6 V)/(1/6) = 3.6 V
になる。といっても電源電圧VDDを超えられない(通常3.3Vを超えられない)
acq_time
取得時間のパラメータの設定
Enumerator | |
---|---|
NRF_SAADC_ACQTIME_3US | 3 us. |
NRF_SAADC_ACQTIME_5US | 5 us. |
NRF_SAADC_ACQTIME_10US | 10 us. |
NRF_SAADC_ACQTIME_15US | 15 us. |
NRF_SAADC_ACQTIME_20US | 20 us. |
NRF_SAADC_ACQTIME_40US | 40 us. |
mode
シングルエンドかディファレンシャルかを設定する。
Enumerator | |
---|---|
NRF_SAADC_MODE_SINGLE_ENDED | Single ended, PSELN will be ignored, negative input to ADC shorted to GND. |
NRF_SAADC_MODE_DIFFERENTIAL | Differential mode. |
シングルエンドはGNDとそのピンの間の電圧を読む事になり、ディファレンシャルはあるピンとその他のピンとの差を読む時の設定する。用途によっては、ディファレンシャルは信号に載ったノイズをキャンセルするので安定的。
burst
Oversamplingする時に、1にすると・・・2のOVERSAMPLE乗回の設定を避ける事ができる。オーバーサンプリングとは・・・というのは・・・
pin_p、 pin_n
どのピンを使うかの設定。ADCはどのピンでも指定できるという訳ではなく上で述べたように指定されている。シングルエンドで測定する時は、pin_n をNRF_SAADC_INPUT_DISABLED に接続。
ADCのイニシャライズ
//initializing of ADC
err_code = nrf_drv_saadc_init(NULL,saadc_callback_handler);
APP_ERROR_CHECK(err_code);
nrf_drv_saadc_initの第一引数は、別の設定として、nrf_drv_saadc_config_t という構造体を用いて、
resolution
oversample
interrupt_priority(割り込み優先度)
low_power_mode
true:低消費電力モード有効
false:低消費電力モード無効
の設定をし、それをここでポインタで指定してやるんだが・・・
指定しない場合は、sdk_configで設定された値になる。ここでは、sdk_configで指定する事にしているので、記述をしないので”NULL”
用意していなかったので、mainの外に、
void static saadc_callback_handler(nrf_drv_saadc_evt_t const *p_event)
{
}
何もしないハンドラー関数を用意してあげて、その関数名を第二引数にいれる。
チャンネルのイニシャライズ
//initializing of Channel
err_code = nrfx_saadc_channel_init(0, &channel_config);
APP_ERROR_CHECK(err_code);
nrf_drv_saadc_channel_initによってADCのチャンネルが有効になる。この関数の第一引数”ゼロ”。実は、これがよくわからない・・・。
uint8_t | channel, |
と記載されているが。今の所の仮説では、後でAD変換しなさいと命令を送る時にも、チャンネルを指定するが、その時にここで、これがチャンネルゼロとしますよ!という宣言ではと。
第二引数は先ほど設定した、channel_config をポインタで渡してあげる。
値の読み込み
ADCの変換された値を格納する変数を定義する。
よくあるのはuint16_tとかで定義するがnrf_saadc_value_t ってのが用意されている。
nrf_saadc_value_t adc_val;
別にuint16_tとかにしても動くはず。
whileの中に以下を記載。
while (true)
{
nrfx_saadc_sample_convert(0,&adc_val);
NRF_LOG_INFO("Read=%x,%d", adc_val,adc_val);
NRF_LOG_INFO("V=" NRF_LOG_FLOAT_MARKER, NRF_LOG_FLOAT(adc_val*(3.3+0.3)/1024));
NRF_LOG_FLUSH();
nrf_delay_ms(500);
}
nrfx_saadc_sample_convertの部分、第一引数は、先ほどチャンネルのイニシャライズした時のチャンネルの番号。変換後の値を格納する変数をポインタで渡す。
テスト回路の作製
51kΩと10kΩをVDD(3.3V)とGNDに直列に接続して、間の点をADCの入力に。
3.3Vx10/(10/51)=0.54Vが出力される。実際は入力が3.27Vと少し低いので0.52Vぐらいが出てくるはず・・・
コードの1024で割っていたのを16384階調に変更。
while (true)
{
nrfx_saadc_sample_convert(0,&adc_val);
NRF_LOG_INFO("Read=%x,%d", adc_val,adc_val);
NRF_LOG_INFO("V=" NRF_LOG_FLOAT_MARKER, NRF_LOG_FLOAT(adc_val*(3.3+0.3)/16384));
NRF_LOG_FLUSH();
nrf_delay_ms(500);
}
コメント
コメントを投稿