さくらのアドベントカレンダー2022 23日目の記事です。
こんにちは、さくらインターネットのこたまごです。
さくらインターネットではクラウド接続向けフルMVNOのSIMとして「さくらのセキュアモバイルコネクト」を提供しています。
また、単純なLTEの回線だけではなく、組み込み向けのプロトコルでクラウド側のプラットフォームとセットで提供する「モノプラットフォーム」と組み合わせた利用も可能です。
標準でサポートするモデム兼MCUとしてNordic社のnRF9160を推奨しています。
Nordic社のnRF9160はワンチップにLTEモデムとARMのMCUを搭載しており、LTEで通信する組み込み開発をこのチップ一枚で行うことができる一風変わったマイコンになっています。
組み込み向けリアルタイムOSのZephyrを利用した "nRF Connect SDK (ncs)" が提供されており、簡単に開発ができる環境が提供されています。
今基板から作って開発しているものが出来上がったらSDKの使い方を公開していこうと思っています。
今日は、SDKの使い方のうち、ドキュメントを漁っても、ググってもなかなか動く状態にできなかったADCについてメモを残しておこうと思います。
NCSはv2系で少し大きめの変更が入っており、v1系の時のサンプルが動かなくなっている部分があるためググって出てきた解説ではダメな時があるので要注意です。
nRF9160 と nRF Connect SDK v2.1.1 でADCを動かす
ADCを利用するためにする作業は3つです
- prj.conf でADCを有効にする
- デバイスツリーファイル (dts) にADCの定義を追加する
- CのコードでADCを利用する
prj.conf
ADCを有効にするために必要なオプションは次の一行だけです。
CONFIG_ADC=y
デバイスツリーファイル
デバイスツリーには以下の定義を追加します。
この例ではnRF9160のアナログ入力のうち AIN7
を利用し、ゲインとして1/6を利用している例です。
&adc {
status = "okay";
channel@0 {
reg = <7>;
zephyr,gain = "ADC_GAIN_1_6";
zephyr,reference = "ADC_REF_INTERNAL";
zephyr,vref-mv = <600>;
zephyr,acquisition-time = <ADC_ACQ_TIME(ADC_ACQ_TIME_MICROSECONDS, 20)>;
zephyr,resolution = <12>;
zephyr,oversampling = <3>;
zephyr,input-positive = <NRF_SAADC_AIN7>;
};
};
Cのコード
抜粋ですが、ADCの初期化とサンプリングを行う関数定義は次のようになります。
#include <drivers/adc.h>
#include <hal/nrf_saadc.h>
static const struct device *adc_dev = DEVICE_DT_GET(DT_NODELABEL(adc));
static const struct adc_channel_cfg battsence_channel_cfg =
ADC_CHANNEL_CFG_DT(DT_CHILD(DT_NODELABEL(adc), channel_0));
int adc_init(void) {
int err;
if (!adc_dev) {
LOG_ERR("device_get_binding adc failed");
return -1;
}
err = adc_channel_setup(adc_dev, &battsence_channel_cfg);
if (err) {
LOG_ERR("Error in adc setup: %d", err);
return -1;
}
return 0;
}
int16_t measure_batt_mv() {
int err;
int16_t m_sample_buffer;
const struct adc_sequence sequence = {
.channels = BIT(7),
.buffer = &m_sample_buffer,
.buffer_size = sizeof(m_sample_buffer),
.resolution = 12,
.oversampling = 3,
};
if (!adc_dev) {
return -1;
}
err = adc_read(adc_dev, &sequence);
if (err) {
LOG_ERR("ADC read err: %d", err);
return -1;
}
double adc_value = (double)m_sample_buffer;
adc_value = adc_value * 3600.0d; // MAX3.6V
adc_value = adc_value / 4095.0d; // 12bit
LOG_DBG("ADC raw value: %d", m_sample_buffer);
LOG_INF("Measured voltage: %d mV", (int)adc_value);
return (int16_t)adc_value;
}
まとめ
nRF9160は超省電力な装置を作ることができるLTE搭載のマイコンです。
省電力のため、バッテリーで駆動させる製品を作ることも出てくるため、電池電圧の計測などADCの利用が必須となってくるでしょう。
ところが、ADCの例が少ないためなかなか動くコードを書くことができませんでした。
本記事は SDK v2.1.1 で実際に動くことをメモとして残しておくことでnRF9160のADCで困る人が減るといいなと思って書きました。
すごくニッチな内容になってしまってすいません...
Merry Christmas and Happy New year !