がれすたさんのDIY日記

電子回路、Python、組み込みシステム開発、自作エフェクターを語るblog

MIMXRT10xxのADCを使ってみる

今回はMIMXRT10xxシリーズのADCを使ってみようと思う。
ペリフェラルの特徴としてまとめると

  • 1MS/sec sample rate
  • 1モジュールに8つのシングルエンド入力
  • single conversion と continuous conversionに対応
  • 12bit,10bit,8bitに対応
  • 下限値、上限値、値の一致、範囲内、範囲外の割り込みに対応
  • Hardware average functionを内蔵

な感じである。
個人的にはValue trigger , Hardware average functionが使えそうだなと感じた。

次に内部をのぞいてみる。

f:id:gsmcustomeffects:20190308162044p:plain
概略

Kinetisだと16bitだったんですが12bitになったんですね。

割り当てピンとしては以下の表を参考にしてほしい。
一つのチャンネルに対して16本の入力ピンがある感じなので好きなとこ使えばいいと思う
ただし、データレジスタの数が8つまでなのでADC1で使える本数は8個までそれ以上使う場合はADC2を使う。

signal descriptor pad
ADC1_IN0 ch1 input 0 GPIO_AD_B1_11
ADC1_IN1 ch1 input 1 GPIO_AD_B0_12
ADC1_IN2 ch1 input 2 GPIO_AD_B0_13
ADC1_IN3 ch1 input 3 GPIO_AD_B0_14
ADC1_IN4 ch1 input 4 GPIO_AD_B0_15
ADC1_IN5 ch1 input 5 GPIO_AD_B1_00
ADC1_IN6 ch1 input 6 GPIO_AD_B1_01
ADC1_IN7 ch1 input 7 GPIO_AD_B1_02
ADC1_IN8 ch1 input 8 GPIO_AD_B1_03
ADC1_IN9 ch1 input 9 GPIO_AD_B1_04
ADC1_IN10 ch1 input 10 GPIO_AD_B1_05
ADC1_IN11 ch1 input 11 GPIO_AD_B1_06
ADC1_IN12 ch1 input 12 GPIO_AD_B1_07
ADC1_IN13 ch1 input 13 GPIO_AD_B1_08
ADC1_IN14 ch1 input 14 GPIO_AD_B1_09
ADC1_IN15 ch1 input 15 GPIO_AD_B1_10

ADC2に関しては割愛(ref manualのTable 63-2. ADC external signalsを参照)

次に仕組み的なものを雑に紹介する。


やってみる

環境としてはForlinx RT1052評価ボードを使う。
写真左の多回転トリマーがADCにつながっていますのでそのピンを使って進めていきます。(ピン的にはGPIO_AD_B0_14

自分はこの環境だが購入とかも直接問い合わせとかでめんどくさいので普通の人は公式の評価ボードであるMIMXRT1050-EVKなんかを使うのがいいと思う。

f:id:gsmcustomeffects:20190401224949p:plain
Forlinx OK1052-C 評価ボード


ハードウエアの用意が終わったところでさっそくやって行きたいわけだがSDKプロジェクトにはADCのサンプルがついている。

  • adc_12b1msps_sar_polling
  • adc_12b1msps_sar_interrupt
  • adc_etc_software_trigger_conv
  • adc_etc_hardware_trigger_conv


これらのサンプルプロジェクトはAPIの使い方について大いに参考になるが別ファイルで記述されているクロックやピンファンクションなどの初期設定で何をやればいいのかわかりにくい。
そのため今回は空プロジェクトからadc_12b1msps_sar_pollingと同様なことをやってみたいと思う。
内容としてはソフトウエアでADCを開始してADC完了後ポーリングAPIにてADCデータレジスタから値の取得を行うというものです。

やることの整理とスキームをまとめると以下のようになります。

  • プロジェクトの作成
  • クロックの設定
  • ピンの設定
  • Conversionの設定
  • Calibrationの設定
  • 割り込みやチャンネルコンフィグの設定
  • コードの出力

ざっとまとめるとこんな感じになるのでクロックの設定からやって行くことにします

プロジェクトの作成

まずは自分の環境にあったチップを選んで新規プロジェクトを作成する。

f:id:gsmcustomeffects:20190430013137p:plain
新規プロジェクト

メモリなどの設定は以下のようにした

f:id:gsmcustomeffects:20190430013226p:plain
メモリコンフィグ

クロックの設定

まずはクロックということでそれの画面に遷移する。

f:id:gsmcustomeffects:20190430013651p:plain
クロック設定にかかわる画面
IMXRT10xxのADCにはクロックソースが3つある(正確には2つ)

  • IPG clock
  • IPG clock divided by 2
  • ADACK(ad asynchronous clock)

ADACKはADCペリフェラル内蔵のクロックソースで、MCUがstopモード中でも変換が可能となっている。
リセット時はIPG clockが設定されている。
ADCモジュール上でクロックに関連は以下の図の点線で囲った部分であり、後段に共通のディバイダを備えていることがわかる。

f:id:gsmcustomeffects:20190421232935p:plain
ADC block diagram

次に実際のクロック設定だが結構楽でペリフェラルツールでプルダウンメニューから選ぶだけで良い。
ちなみにIPGを選ぶ場合はクロックが早すぎると問題があるので設定に注意したい。

f:id:gsmcustomeffects:20190415025544p:plain
ペリフェラルツールの設定例

自分の場合はこのようにした。

  • Clock source : Asynchronous Clock
  • Clock source frequency : 10MHz
  • Clock source divider : Do not divide
  • sample time : 6 clocks(short sample mode)

Start asynchronous clock outputに関してはADCx_GCのADACKENに解説がありどちらでも動くには動く。

  • OFF:変換がアクティブ時にON
  • ON:asynchronous clockが常にONになるため初回変換時に数クロック分早くなる。(クロック起動サイクル分がなくなるため)

クロックについてさらに詳しく知りたければリファレンスマニュアルのCCMの章を読むといいだろう。

ピンの設定

特にこうしろってのはないので自分の使いたいピンを設定してください

f:id:gsmcustomeffects:20190429234550p:plain
ピンコンフィグ

Conversion設定

次にConversionの設定です。

Conversion Timeの計算方法はリファレンスマニュアルにも書いてあるが
\begin{equation}
ConversionTime = SFCAdder + AverageNum * (BCT + LSTAdder)
\end{equation}

で計算できる。変換部分を詰めるなら知っとくべきだが補助ツールでだいたいの設定はできてしまうので今回の例では設定部分だけ書く

f:id:gsmcustomeffects:20190429211654p:plain
ペリフェラル設定(Conversion)

Calibration設定

最後にADCの精度確保のために初期キャリブレーションを行う必要がある。

これに関してはペリフェラルツールだとチェック入れるだけ

f:id:gsmcustomeffects:20190429233243p:plain
ペリフェラル設定(キャリブレーション

割り込みやチャンネルコンフィグの設定

f:id:gsmcustomeffects:20190430010958p:plain
割り込み+コンフィグ設定

コード出力および記述

これで一通りの設定が終わったのでコードを出力する。

f:id:gsmcustomeffects:20190430014322p:plain
コードの出力

初期化部分が出力できたらコードを書いていく。

書くとは言っても結構コンパクトにおさまる。ADC結果をprintfしていく感じ

f:id:gsmcustomeffects:20190430015452p:plain
コードの記述と解説

UART出力を確認するとこんな感じ

f:id:gsmcustomeffects:20190430015842p:plain
Teratermでの出力

割り込みについて

割り込みに関してはツールでチェック入れるだけでできて簡単なのでコードとして何が出力されるか示す。
EnableIRQ APIをコールしARMコア自体に割り込みの有無を教える

EnableIRQ(ADC1_IRQn);
EnableIRQ(ADC2_IRQn);//使うほうを有効にする。両方有効ならそれでもいい

チャンネル設定構造体メンバに割り込み有効

adcChannelConfigStruct.enableInterruptOnConversionCompleted = true;
ADC_SetChannelConfig(DEMO_ADC_BASE, DEMO_ADC_CHANNEL_GROUP, &adcChannelConfigStruct);

ハンドラの定義

void ADC1_IRQHandler(void)//ADC2を使う場合は2のハンドラを使う
{
    g_AdcConversionDoneFlag = true;
    /* Read conversion result to clear the conversion completed flag. */
    g_AdcConversionValue = ADC_GetChannelConversionValue(DEMO_ADC_BASE, DEMO_ADC_CHANNEL_GROUP);
    g_AdcInterruptCounter++;
/* Add for ARM errata 838869, affects Cortex-M4, Cortex-M4F Store immediate overlapping
  exception return operation might vector to incorrect interrupt */
#if defined __CORTEX_M && (__CORTEX_M == 4U)
    __DSB();
#endif
}

メモ

その他の機能について

サンプルプログラムとしてはSDK付属の物がいくつかあるのでそれを参考にするとハードウエアトリガーで動かすことも可能。
以下4つがSDKに含まれているので使う際は参考にするといい

  • adc_12b1msps_sar_polling
  • adc_12b1msps_sar_interrupt
  • adc_etc_software_trigger_conv
  • adc_etc_hardware_trigger_conv