5
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Nordic nRF52840 の 32k クロックを内蔵 RC で使う

Last updated at Posted at 2020-02-09

Nordic の nRF52840 は クロックが2つ必要で、メインクロックと32.768kHzの低速クロック。

低速クロックはカレンダー以外にも通信のタイミングなどに使っているらしい。低速クロックの精度が狂うと通信に影響がある。特に Bluetooth では 250ppm 以内に精度を押さえないといけないらしい。

低速クロックは外部クリスタルをつなげるようになっていて(Low frequency crystal oscillator : LFXO)、SDKでもそれ前提の設定となっている。

しかしながら外部クリスタルを省略して、内部RC発振器やメインクロックを分周して32kクロックを賄うこともできる。

外部クリスタル LFXO との違い

ではそれらを使った場合はどのような違いがあるか?

メインクロックを分周(LFSYNT)する場合

https://devzone.nordicsemi.com/f/nordic-q-a/35989/clock-source-on-ble_app_uart
によると、LFSYNTは消費電力の点で不利。

内部RC発振器(Low frequency RC oscillator : LFRC )を使った場合:

内部RC発振器駆動のための消費電流増加

nRF52840_PS_v1.0.pdf の

5.4.4.3 Low frequency crystal oscillator (LFXO)
5.4.4.4 Low frequency RC oscillator (LFRC), Normal mode

によると、

LFXO 0.23uA
LFRC 0.7uA

となっている。

精度低下のための消費電流増加

また精度低下のために、後述のキャリブレーションおよびBluetoothリスニング時間の増大(Window widening)が必要となる。それぞれ更に消費電力が拡大する。

cf., nRF52832ではあるが実測値を含む具体的なデータ https://devzone.nordicsemi.com/f/nordic-q-a/14214/how-much-current-consumption-when-we-use-internal-32k-rc

通信プロトコルの制限

ANTでは精度の関係で内蔵RCは使えないらしい(精度 50ppm が必要)。

内蔵 RC の使用

では、内蔵 RC を使う設定にするにはどうしたらいいか? SoftDevice を使う場合と使わない場合で方法は異なる。ここでは、SoftDeviceを使う場合について。

必要なキャリブレーション間隔

RC 発振器は精度が2%と大変悪い。
BLE stack を使う場合、250ppm 以内に収める必要があるので一定時間ごとにキャリブレーションを行って精度を保つ。8秒ごとのキャリブレーション、および0.5℃の変化時には4秒毎のキャリブレーションが推奨されている。

cf., https://infocenter.nordicsemi.com/topic/com.nordic.infocenter.s132.api.v7.0.1/structnrf__clock__lf__cfg__t.html

sdk_config.h の設定

元々の LFXC を使う設定は nRF_SoftDevice - NRF_SDH_ENABLED - clock の項目において下記のようになっている。


//==========================================================

// <h> Clock - SoftDevice clock configuration

//==========================================================
// <o> NRF_SDH_CLOCK_LF_SRC  - SoftDevice clock source.

// <0=> NRF_CLOCK_LF_SRC_RC 
// <1=> NRF_CLOCK_LF_SRC_XTAL 
// <2=> NRF_CLOCK_LF_SRC_SYNTH 

# ifndef NRF_SDH_CLOCK_LF_SRC
# define NRF_SDH_CLOCK_LF_SRC 1
# endif

// <o> NRF_SDH_CLOCK_LF_RC_CTIV - SoftDevice calibration timer interval. 
# ifndef NRF_SDH_CLOCK_LF_RC_CTIV
# define NRF_SDH_CLOCK_LF_RC_CTIV 0
# endif

// <o> NRF_SDH_CLOCK_LF_RC_TEMP_CTIV - SoftDevice calibration timer interval under constant temperature. 
// <i> How often (in number of calibration intervals) the RC oscillator shall be calibrated
// <i>  if the temperature has not changed.

# ifndef NRF_SDH_CLOCK_LF_RC_TEMP_CTIV
# define NRF_SDH_CLOCK_LF_RC_TEMP_CTIV 0
# endif

// <o> NRF_SDH_CLOCK_LF_ACCURACY  - External clock accuracy used in the LL to compute timing.

// <0=> NRF_CLOCK_LF_ACCURACY_250_PPM 
// <1=> NRF_CLOCK_LF_ACCURACY_500_PPM 
// <2=> NRF_CLOCK_LF_ACCURACY_150_PPM 
// <3=> NRF_CLOCK_LF_ACCURACY_100_PPM 
// <4=> NRF_CLOCK_LF_ACCURACY_75_PPM 
// <5=> NRF_CLOCK_LF_ACCURACY_50_PPM 
// <6=> NRF_CLOCK_LF_ACCURACY_30_PPM 
// <7=> NRF_CLOCK_LF_ACCURACY_20_PPM 
// <8=> NRF_CLOCK_LF_ACCURACY_10_PPM 
// <9=> NRF_CLOCK_LF_ACCURACY_5_PPM 
// <10=> NRF_CLOCK_LF_ACCURACY_2_PPM 
// <11=> NRF_CLOCK_LF_ACCURACY_1_PPM 

# ifndef NRF_SDH_CLOCK_LF_ACCURACY
# define NRF_SDH_CLOCK_LF_ACCURACY 7
# endif

このうち、有効なディレクティブは以下の4つ。


# define NRF_SDH_CLOCK_LF_SRC 1
# define NRF_SDH_CLOCK_LF_RC_CTIV 0
# define NRF_SDH_CLOCK_LF_RC_TEMP_CTIV 0
# define NRF_SDH_CLOCK_LF_ACCURACY 7

これらを以下のように変更

NRF_SDH_CLOCK_LF_SRC

SoftDevice clock source.


// <0=> NRF_CLOCK_LF_SRC_RC 

ということなので 0 を指定。

NRF_SDH_CLOCK_LF_RC_CTIV

SoftDevice calibration timer interval.

ここに設定する値は rc_ctiv に設定する値と同様に 1/4 秒単位だと思うけど本当かな?
ドキュメント
https://infocenter.nordicsemi.com/topic/sdk_nrf5_v16.0.0/group__nrf__sdh__config.html

は、

Note
This is an NRF_CONFIG macro.

とあるだけで役に立たない。NRF_CONFIG macroって何だ?

調べてみたら NRF_CONFIG macro についてはわからなかったが NRF_SDH_CLOCK_LF_RC_CTIV は SDK 中の components/softdevice/common/nrf_sdh.c 中で、以下のように使われていた。


    nrf_clock_lf_cfg_t const clock_lf_cfg =
    {
        .source       = NRF_SDH_CLOCK_LF_SRC,
        .rc_ctiv      = NRF_SDH_CLOCK_LF_RC_CTIV,
        .rc_temp_ctiv = NRF_SDH_CLOCK_LF_RC_TEMP_CTIV,
        .accuracy     = NRF_SDH_CLOCK_LF_ACCURACY
    };

nrf_clock_lf_cfg_t 構造体は先に示した https://infocenter.nordicsemi.com/topic/com.nordic.infocenter.s132.api.v7.0.1/structnrf__clock__lf__cfg__t.html
で定義されていて、rc_ctivは 1/4 秒単位。

ここでは下記の NRF_SDH_CLOCK_LF_RC_TEMP_CTIV と合わせてタイマー間隔を決定する。今回はここで温度変化が0.5℃以上ある場合の間隔を指定し、推奨値を満たすために16を指定する。これでタイマー間隔は4秒間隔になる。

NRF_SDH_CLOCK_LF_RC_TEMP_CTIV

SoftDevice calibration timer interval under constant temperature.
How often (in number of calibration intervals) the RC oscillator shall be calibrated if the temperature has not changed.

温度が変更されていない場合のキャリブレーションの頻度。単位は先の先にタイマー間隔を4秒にした。温度が変更されていない場合のキャリブレーション間隔の推奨値は8秒。ここで2を指定することでタイマー2回毎にキャリブレーションが行われる。

NRF_SDH_CLOCK_LF_ACCURACY

External clock accuracy used in the LL to compute timing.

Window widening などに関連するのではないかな? RC 発振器でキャリブレート後の精度 250ppm として 0 を指定するのが良さそうですね・・・

設定値

結局、設定値はこうなります。


# define NRF_SDH_CLOCK_LF_SRC 0
# define NRF_SDH_CLOCK_LF_RC_CTIV 16
# define NRF_SDH_CLOCK_LF_RC_TEMP_CTIV 2
# define NRF_SDH_CLOCK_LF_ACCURACY 0

これらを反映した SDK_config.h の Clock セクションは下記の通り。


//==========================================================

// <h> Clock - SoftDevice clock configuration

//==========================================================
// <o> NRF_SDH_CLOCK_LF_SRC  - SoftDevice clock source.

// <0=> NRF_CLOCK_LF_SRC_RC 
// <1=> NRF_CLOCK_LF_SRC_XTAL 
// <2=> NRF_CLOCK_LF_SRC_SYNTH 

# ifndef NRF_SDH_CLOCK_LF_SRC
# define NRF_SDH_CLOCK_LF_SRC 1
# endif

// <o> NRF_SDH_CLOCK_LF_RC_CTIV - SoftDevice calibration timer interval. 
# ifndef NRF_SDH_CLOCK_LF_RC_CTIV
# define NRF_SDH_CLOCK_LF_RC_CTIV 0
# endif

// <o> NRF_SDH_CLOCK_LF_RC_TEMP_CTIV - SoftDevice calibration timer interval under constant temperature. 
// <i> How often (in number of calibration intervals) the RC oscillator shall be calibrated
// <i>  if the temperature has not changed.

# ifndef NRF_SDH_CLOCK_LF_RC_TEMP_CTIV
# define NRF_SDH_CLOCK_LF_RC_TEMP_CTIV 0
# endif

// <o> NRF_SDH_CLOCK_LF_ACCURACY  - External clock accuracy used in the LL to compute timing.

// <0=> NRF_CLOCK_LF_ACCURACY_250_PPM 
// <1=> NRF_CLOCK_LF_ACCURACY_500_PPM 
// <2=> NRF_CLOCK_LF_ACCURACY_150_PPM 
// <3=> NRF_CLOCK_LF_ACCURACY_100_PPM 
// <4=> NRF_CLOCK_LF_ACCURACY_75_PPM 
// <5=> NRF_CLOCK_LF_ACCURACY_50_PPM 
// <6=> NRF_CLOCK_LF_ACCURACY_30_PPM 
// <7=> NRF_CLOCK_LF_ACCURACY_20_PPM 
// <8=> NRF_CLOCK_LF_ACCURACY_10_PPM 
// <9=> NRF_CLOCK_LF_ACCURACY_5_PPM 
// <10=> NRF_CLOCK_LF_ACCURACY_2_PPM 
// <11=> NRF_CLOCK_LF_ACCURACY_1_PPM 

# ifndef NRF_SDH_CLOCK_LF_ACCURACY
# define NRF_SDH_CLOCK_LF_ACCURACY 7
# endif

5
4
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
5
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?