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
XAIOを使っている場合は、取り出しされているのは、AIN0 P0.02、AIN1 P0.03、AIN4 P0.28、AIN5 P0.29の4つのピンになる。


コーディング

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

で示されて、ゲインで割る事になる
Enumerator
NRF_SAADC_GAIN1_6 

Gain factor 1/6.

NRF_SAADC_GAIN1_5 

Gain factor 1/5.

NRF_SAADC_GAIN1_4 

Gain factor 1/4.

NRF_SAADC_GAIN1_3 

Gain factor 1/3.

NRF_SAADC_GAIN1_2 

Gain factor 1/2.

NRF_SAADC_GAIN1 

Gain factor 1.

NRF_SAADC_GAIN2 

Gain factor 2.

NRF_SAADC_GAIN4 

Gain factor 4.

仮に 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 に接続。

Enumerator
NRF_SAADC_INPUT_DISABLED 

Not connected.

NRF_SAADC_INPUT_AIN0 

Analog input 0 (AIN0).

NRF_SAADC_INPUT_AIN1 

Analog input 1 (AIN1).

NRF_SAADC_INPUT_AIN2 

Analog input 2 (AIN2).

NRF_SAADC_INPUT_AIN3 

Analog input 3 (AIN3).

NRF_SAADC_INPUT_AIN4 

Analog input 4 (AIN4).

NRF_SAADC_INPUT_AIN5 

Analog input 5 (AIN5).

NRF_SAADC_INPUT_AIN6 

Analog input 6 (AIN6).

NRF_SAADC_INPUT_AIN7 

Analog input 7 (AIN7).

NRF_SAADC_INPUT_VDD 

VDD as input.


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の部分、第一引数は、先ほどチャンネルのイニシャライズした時のチャンネルの番号。変換後の値を格納する変数をポインタで渡す。


テスト回路の作製



適当な抵抗で3.3Vを分圧してみた。
51kΩと10kΩをVDD(3.3V)とGNDに直列に接続して、間の点をADCの入力に。
3.3Vx10/(10/51)=0.54Vが出力される。実際は入力が3.27Vと少し低いので0.52Vぐらいが出てくるはず・・・



実際の出力を表示した結果が上で、ちょっとばらつきは大きいが値は出ている。



14ビットに設定してみる。2か所をプルダウンで14bitを選択
コードの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);
    }

階調があがっているのが確認できた。





コメント

このブログの人気の投稿

Attiny85とAQM0802A(LCD)のI2C接続

Attiny85 FuseRest

HS101 STM32の自作お手軽オシロスコープ