0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

nRF52840のADCで電源電圧を読み出してみた。

Posted at

要約

Nordic Semiconductor社製SoC nRF52840のAD変換器でVDDH電圧, VDD電圧を読み出す。

コード

prj.conf

CONFIG_ADC=y

app.overlay

/ {
	zephyr,user {
		io-channels = <&adc 0>, <&adc 1>;
	};
};

&adc {
	#address-cells = <1>;
	#size-cells = <0>;
	status = "okay";
	channel@0 {
		reg = <0>;
		zephyr,gain = "ADC_GAIN_1_2";
		zephyr,reference = "ADC_REF_INTERNAL";
		zephyr,acquisition-time = <ADC_ACQ_TIME_DEFAULT>;
		zephyr,input-positive = <NRF_SAADC_VDDHDIV5>;
		zephyr,resolution = <12>;
	};
	channel@1 {
		reg = <1>;
		zephyr,gain = "ADC_GAIN_1_6";
		zephyr,reference = "ADC_REF_INTERNAL";
		zephyr,acquisition-time = <ADC_ACQ_TIME_DEFAULT>;
		zephyr,input-positive = <NRF_SAADC_VDD>;
		zephyr,resolution = <12>;
	};
};

C

#include <zephyr/drivers/adc.h>

#define DT_SPEC_AND_COMMA(node_id, prop, idx) \
  ADC_DT_SPEC_GET_BY_IDX(node_id, idx),

static const struct adc_dt_spec adc_channels[] = {
    DT_FOREACH_PROP_ELEM(DT_PATH(zephyr_user), io_channels, DT_SPEC_AND_COMMA)};

static uint16_t buf[ARRAY_SIZE(adc_channels)];
static struct adc_sequence sequence[ARRAY_SIZE(adc_channels)];

void adc_initialize(void) {
  int err;
  for (size_t i = 0U; i < ARRAY_SIZE(adc_channels); i++) {
    if (!adc_is_ready_dt(&adc_channels[i])) {
      return;
    }
    err = adc_channel_setup_dt(&adc_channels[i]);
    if (err < 0) {
      return;
    }
    sequence[i].buffer = &buf[i];
    sequence[i].buffer_size = sizeof(buf[i]);
  }
}

void adc_update(void) {
  int err;
  for (size_t i = 0U; i < ARRAY_SIZE(adc_channels); i++) {
    (void)adc_sequence_init_dt(&adc_channels[i], &sequence[i]);
    err = adc_read_dt(&adc_channels[i], &sequence[i]);
    if (err < 0) {
      return;
    }
  }
}

int32_t adc_get(const uint8_t kIdx) {
  int err;
  int32_t val_mv;
  if (ARRAY_SIZE(adc_channels) <= kIdx) {
    return -1;
  }

  if (adc_channels[kIdx].channel_cfg.differential) {
    val_mv = (int32_t)((int16_t)buf[kIdx]);
  } else {
    val_mv = (int32_t)buf[kIdx];
  }

  if (0 == kIdx) {
    val_mv *= 5;  // VDDH DIV 5
  }

  err = adc_raw_to_millivolts_dt(&adc_channels[kIdx], &val_mv);
  if (err < 0) {
    return -1;
  } else {
    return val_mv;
  }
  return -1;
}

設計メモ

  • 内蔵リファレンス電圧は0.6V。(余談: nRF54L15は0.9Vらしい)
  • VDDの動作範囲は1.7V〜3.6Vなので、Gainは1/6倍を選択すればリファレンス電圧を超えない。
  • VDDHの動作範囲は2.5V〜5.5V、AD変換器の入力時点で1/5されているので、Gainは1/2倍を選択すればリファレンス電圧を超えない。

今後の取り組み

  • VDDHDIV5はインピーダンスが高いためか、直前のAD変換結果の影響を受けているような気がするので、アクイジションタイムを長くする、事前にサンプルホールドキャパシタを放電させる等の対策を実施したい。

動作確認環境

  • toolchains v2.6.2
  • nRF Connect SDK v2.6.2
  • MDBT50Q-DB-40 (raytac_mdbt50q_db_40_nrf52840)

参考文献

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?