ADコンバータ【STM32のADコンバータ詳細】
STM32マイコンのADコンバータはとても高機能なために、初心者・入門者は単純なものから順に理解しながらステップアップしていくのがよいと思われます。
この章では1チャンネルのアナログ入力を必要なときだけ手動で取得するシングルモード変換方式から複数チャネルのアナログ入力を連続して自動取得してDMA送信でメモリに転送する方式までを解説しています。
STAM32のADコンバータ
マイコンにはADコンバータ(AD変換器)が内蔵されていて、アナログ信号をマイコンに取り入れてデジタル信号に変換することができます。STM32のADコンバータは12ビットの分解能でSTM32では最大3.3Vですので3.3Vを4096(=212)分割した分解能で数値を扱うことができます。
STM32のADコンバータは変換速度もとても速く高性能で一つのADコンバータ回路で複数のチャネルの切り替えできる高機能なものです。複数のADコンバータをもつものもあり、単にAD変換値を取得するだけでも数種類の方法があります。この章ではこのSTM32マイコンの多機能なADコンバータの使い方について解説していきます。
すべての機能を使いこなすのではなく必要に応じて応用の幅を広げていけばいいと思います。これも一度、使い方を知って理解できればあとはアプリケーションに応用するだけです。
ADコンバータはアナログ信号を扱うので、少しアナログ回路を意識して使用する必要があります。アナログ信号をデジタル信号に変換するのにサンプリングホールドというコンデンサをつかったアナログ変換回路をもっていて変換時に電流が流れやすいほどコンデンサにチャージ(蓄電)する時間が短くてすむので高速に変換できるものです。
ADコンバータに接続するアナログセンサなどには内部抵抗というものをもっていてこの抵抗が小さいほど電流が流れやすいのでより高速の変換ができます。この内部抵抗は出力インピーダンスとも呼ばれるもので、ADコンバータを使用する際には知っておく必要があります。
インピーダンスは直流を含む交流回路の抵抗ですが、ここでは直流の内部抵抗に置き換えて説明します。図中でADコンバータの回路においては出力インピーダンスRoと入力機器の入力インピーダンスRiの関係はRo<<Riが好ましいです。入力側のRiは固定のもので考えると、出力機器側のインピーダンスRoが小さいほど負荷電流iによる電圧降下の影響も小さく、入力機器側に電流も流しやすくなるからです。
STM32のデータシートによるとADコンバータと接続する機器の出力インピーダンスとAD変換にかかる時間は下表になります。これはADコンバータの供給クロックが14MHzであるときの接続できるインピーダンス最大値を示しています。この表からインピーダンスが小さいほどAD変換にかかる時間が短いことがわかります。
シングルモードで都度変換
まず、STM32マイコンのADコンバータの概要をまとめてから実際のプログラムを例に解説をしていきます。
STM32マイコンのADコンバータの設定は高機能なだけに他のペリフェラルに比べても設定項目も多いですが、はじめに理解してさえしてしまえばあとはモジュールとしてブロック化しアプリケーションに活かすだけです。
① ADC1にクロック供給
使用するADC1コンバータにクロックを供給します。APB2バスに接続していますのでAPB2に供給します。
② ADC1のクロック設定
ADコンバータはAPB2の先にあるADコンバータ専用プリスケーラーを介していますのでこの分周比をRCC_ADCCLK関数で設定します。この関数の引数RCC_PCLK2では分周比を指定します。ここでは分周比は6分の1を指定し、ADコンバータへのクロックは12MHz(72MHz/6)としています。入力機器の出力インピーダンスのところでは動作クロックが14MHzを前提にしていたためにそれに最も近い12MHzに設定しています。
③ ADC1入力ポートGPIOの設定
使用するADCの入力ポートGPIOの設定を行います。PA1にアナログ入力を指定します。
④ ADコンバータの初期設定
ADコンバータの初期設定を実行します。はじめのADC_DeInit関数はリセット直後の初期状態に戻すもので一応実行しておきます。初期化はADC_Init関数を実行します
ADコンバータ初期化関数実行例: ADC_Init(ADC1, &ADC_InitStructure);
関数の第1引数には設定対象のADコンバータ(ADC1-3:マイコンによります)を指定し、第2引数は構造体メンバになっていて以下に示します。
ADC_Modeメンバでは単独か複数のADコンバータを使用するときのモードを指定します。単独の場合は独立モード(ADC_Mode_Independent)、複数のADコンバータを使用する場合にデュアルモードで変換時間の効率をあげるためにさまざまな方式を指定できます。
例えば2つのADC1とADC2を使う場合でそれぞれ各ADコンバータのグループとして使用チャネルの変換順序を登録していると、同時に変換をし、変換後次の順序のチャネルを順次変換するのを繰り返すのが並列レギュラ変換モード(ADC_Mode_RegSimult)です。他に複数のADコンバータを連動させたり、タイミングを合わせたりする方式もありますが、とりあえずこの2つのモードを知っておけばよいのではないでしょうか。他のモード詳細は各マイコンのレファレンスマニュアルに記載しています。
ADC_ScanConvModeメンバでは1つのADコンバータには複数のチャネルを持っていて使用するチャネルの変換順序などを登録しておくのですが、この登録チャネルを一度に連続変換するのがスキャンモードで、一定数ずつ変換するのが分割スキャンモードです。複数チャネル時はスキャンモード(ENABLE)の指定でいいと思います。
ADC_ContinuousConvModeメンバは変換を連続に行う連続変換モードと変換開始コマンドADC_SoftwareStartConvCmd関数を与えるときだけ変換を行うシングルモードがあります。
連続変換モードは一度変換を開始すると変換は繰り返すのでアプリケーションプログラム内で任意のタイミングで最新の変換値が取得できます。対してシングルモードは変換値を取得したいときだけ実行するため、消費電力を抑えることができますが、変換にはある程度時間がかかるので一定時間待つ必要があります。
ADC_ExternalTrigConvメンバはタイマイベントで変換を開始する時点を決める場合に指定します。使用しない場合はトリガなし(ADC_ExternalTrigConv_None)を指定します。
STM32マイコンのADコンバータの変換結果は12ビットですが、数値を格納するレジスタは16ビットなので格納方法を右詰か左詰の指定をします。通常はLSB側の下12桁右詰(ADC_DataAlign_Right)に格納でよいと思います。
使用するチャネル数を指定します。サンプルでは1チャンネル使用するので1にしています。
各メンバの指定が終了しましたので、初期化関数ADC_Init(ADC1, &ADC_InitStructure)を実行します。
⑤ ADコンバータの有効化
これまでで、ADコンバータの初期化ができましたのでここでADC_Cmd関数を実行してADコンバータを有効化します。
ADコンバータ有効化関数実行例: ADC_Cmd(ADC1, ENABLE);
関数の第1引数には設定対象のADコンバータ(ADC1-3:マイコンによります)を指定し、第2引数はENABLEで有効、DISABLEで無効となります。
⑥ ADコンバータのキャリブレーション
他のペリフェラルではこれで設定は完了ですがADコンバータではもうひと手間必要です。それが、キャリブレーション(校正)です。このキャリブレーションは各マイコンの製品個体差を補正するものですのでADコンバータの初期化を行うたびに実行します。
キャリブレーション手順はまずキャリブレーション内容を初期化するためにADC_ResetCalibration関数を実行し、その後キャリブレーションをADC_StartCalibration関数で実行します。それぞれの関数は時間がかかるためステータスで完了を確認しています。
⑦ AD変換対象の変換開始
これでいつでもADコンバータによる変換値を取得できます。プログラム例ではADC1のCH1シングルモードの例ですので都度ADC_RegularChannelConfig関数およびADC_SoftwareStartConvCmd関数を実行し変換を開始します。
ADコンバータを使用するには変換の対象となるチャネルをレギュラ変換グループに登録して指定する必要があります。これを行うのにADC_RegularChannelConfig関数を使用して指定します。
レギュラ変換グループ登録関数実行例:
ADC_RegularChannelConfig (ADC1,ADC_Channel_1,1,ADC_SampleTime_13Cycles5);
関数の第1引数には設定対象のADコンバータ(ADC1-3:マイコンによります)を指定、第2引数はチャネル0から17まで指定(ADC_Channel_1 - ADC_Channel_17)、第3引数は変換順序を1から16で指定します。チャネルが1つだけの場合は1とします。 第4引数はサンプリングタイムを指定します。
入力機器の出力インピーダンスが10kΩのためサンプリングタイムは13.5サイクルを指定します。
続いてADC_SoftwareStartConvCmd関数を実行して変換を開始します。
変換開始関数実行例:
ADC_SoftwareStartConvCmd(ADC1,ENABLE);//変換開始
while(ADC_GetFlagStatus(ADC1,ADC_FLAG_EOC)==RESET);//変換待機
ADCValue_CH1=ADC_GetConversionValue(ADC1);//変換値取得(16ビット)
シングルモードでは都度実行のため、変換にかかる時間待機してから変換値を取得します。変換が完了したかどうかをADC_GetFlagStatus関数で確認できます。この関数は使用中のADコンバータの状態をフラグで確認することができます。ここでは変換終了通知フラグのADC_FLAG_EOCがSET(=1)になるまで待機しています。
変換終了後、ADC_GetConversionValue関数を実行して変換値を取得します。関数の引数は対象のADコンバータ(ADC1-3:マイコンによります)を指定します。
これらのコマンドをセットで実行するとアプリケーションプログラム内の任意のタイミングでAD変換値を取得できます。
連続変換モード
これまではシングルモードでの設定および変換値取得までみてきました。このシングルモードは単純で、都度実行して変換値を取得するために消費電力も小さくてよいのですが、変換にかかる時間が大きいため変換が完了するまで待機しなければなりません。
そこで、連続変換モードを指定してADC_SoftwareStartConvCmd関数を一度実行し変換を開始すると自動的に変換が繰り返されますのでいつでも最新の変換値が取得できます。連続変換モードはADC_ContinuousConvModeメンバをENABLEするだけです。
複数チャネルでの変換
これまではチャネル数は1つで取り扱ってきました。チャネルが複数ある場合の変換はどうなるでしょうか。
シングルモードで複数チャネルを変換する場合はAD変換開始のたびにレギュラ変換グループ登録ADC_RegularChannelConfig関数を実行してチャネル指定する必要があります。これは単独チャネルの変換を複数チャネル分実行するため、単純な方式なのですが効率が悪くチャネル数が多い場合は実用的とはいえません。
そこで複数のチャネルの場合に連続変換モードで変換を行う方式をみてみます。
複数チャネルの連続変換モードでは初期設定時にチャネル数やとチャネルの変換順序を指定します①②③。
連続変換モードではチャネルごとの変換値を指定した配列変数に自動で格納するのですが、これはDMA(Direct Memory Access)と呼ばれる技術が使われます④。DMAは自動的にレジスタとメモリ間の処理をCPU関与なしに行います。DMAに関してはのちに詳細を解説しますのでここでは省略します。
STM32マイコンではADコンバータは複数チャネルの変換にはDMAと組み合わせて使うことが必要不可欠です。
連続変換によりプログラムが簡素化されたように変換にかかる時間も短縮されます。
ここまでで、ADコンバータの基本の使い方を解説してきました。
STM32マイコンでは実際のアプリケーションにおいて、チャネル数が増えた場合や、複数のADコンバータを同時に低電力で効率よく使用するなど高度な使い方にも対応できますが、基本はこれまでの解説のもので十分対応できます。