MSP432 ADC


ADC・・・これまでArduinoとかSTM32とか触っていても、MSP本格的で初心者には難易度が高い。そもそもググって出てくる量が違う。いろいろ調べたが、本家のMSP432_Driver_Libraryのマニュアルが実は一番わかりやすい。ここの例題を(自己流で)解説する。

はじめの例題として、Exampleに収録されている"adc14_multiple_channel_no_repeat
"を上から解釈していく。8個のマルチチャンネルのADCの値を読み込むというサンプル。解釈するといっても、理解は間違っているかもしれない・・・が他のソースに何が書いてあるかは理解できるようにはなる。

【サンプルコードのインポートから動作】

Resource Explorerから、adc14_multiple_channel_no_repeatを見つけ出してインポートのボタンを押す。

ソースコードの
上の方に、resultsBuffer[8]というのがあるので、右クリックしてAdd Watch Expressionで監視対象にいれる。

さすがに、TI社が書いているコードなのでエラーは発生しないから、そのままデバッグボタン。

このサンプルコードは、ユーザがデバッグを進めた時(F8ボタンを押した時)に1度だけ、その状態の最後の状態を配列に格納する。Add Watch Expressionで監視していたresultsBufferの配列になんらかの数字がはいることが確認できる(浮いているのでゼロにはならない)

*****ここからソースを解釈****

【おまじない】

    /* Halting WDT  */

    MAP_WDT_A_holdTimer();

    MAP_Interrupt_enableSleepOnIsrExit();

このあたりはおまじない的。WDT_A_holdTimer():暴走防止のウォッチドッグタイマーを停止させて、Interrupt_enableSleepOnIsrExit();で低消費電力化のためにインターラプトしている間はMPUを止めてしまうという記述。

memset(void *buf, int ch, size_t n);

はC言語の基本的な命令。bufの先頭からnバイト分にchをセットする。

memset(resultsBuffer, 0x00, 8 * sizeof(uint16_t));

なので、uint16_tの大きさ16ビット8個分に0x00を入れることになる。

【レファレンス電圧の設定】

/* Setting reference voltage to 2.5  and enabling reference */

    MAP_REF_A_setReferenceVoltage(REF_A_VREF2_5V);

    MAP_REF_A_enableReferenceVoltage();

MSP432のADCはリファレンス電圧を選択することがで、1.2V、1.45V,2.5V、3.3Vから選べる。この部分でそれを実行していている。

【初期化】

いろんなモード(シングル、リピート)があるが、初期化は同じ。まずシングル、1つの入力を得る事から理解をめざす。

ADC14をENABLE状態にして動作するクロックを決めてあげる作業をする。

    /* Initializing ADC (MCLK/1/1) */

    MAP_ADC14_enableModule();

    MAP_ADC14_initModule(ADC_CLOCKSOURCE_MCLK, ADC_PREDIVIDER_1, ADC_DIVIDER_1,0);

クロックのお勉強はどこかでするとして、ADC_CLOCKSOURCE_ADCOSC(25MHz)とか、ADC_CLOCKSOURCE_MCLK(3MHz)を指定して、分周率ADC_PREDIVIDERと、ADC_DIVIDERを決める。PRE(1,4,32,64)で前もって分けてから、DIVIDER(1,2,・・・8)でさらに分ける事になる。

【ピンの指定】

    /* Configuring GPIOs for Analog In */

    MAP_GPIO_setAsPeripheralModuleFunctionInputPin(GPIO_PORT_P5,

            GPIO_PIN5 | GPIO_PIN4 | GPIO_PIN3 | GPIO_PIN2 | GPIO_PIN1

                    | GPIO_PIN0, GPIO_TERTIARY_MODULE_FUNCTION);

    MAP_GPIO_setAsPeripheralModuleFunctionInputPin(GPIO_PORT_P4,

            GPIO_PIN7 | GPIO_PIN6, GPIO_TERTIARY_MODULE_FUNCTION);

MAP_GPIO_setAsPeripheralModuleFunctionInputPinという関数。直訳すると”一般用途の入出力を周辺機器モジュール関数のインプットピンにする”(と解釈している)。Inputと対にOutputもあり、まず方向を決めて、どのピンかを指定する。モードというのが最後の引数になっていてGPIO_TERTIARY_MODULE_FUNCTIONとあり、むろんprimary, secondary そして ternary と3つあるが、これらの違いは正直わかっていない。例題を見る限りは、ADCではGPIO_TERTIARY_MODULE_FUNCTIONを使っている・・・

【メモリの設定】

    /* Configuring ADC Memory (ADC_MEM0 - ADC_MEM7 (A0 - A7)  with no repeat)

     * with internal 2.5v reference */

    MAP_ADC14_configureMultiSequenceMode(ADC_MEM0, ADC_MEM7, false);

    MAP_ADC14_configureConversionMemory(ADC_MEM0,

            ADC_VREFPOS_INTBUF_VREFNEG_VSS,

            ADC_INPUT_A0, false); 以下中略・・・

 MAP_ADC14_configureSingleSampleMode:

シングルで1つだけADCする時のメモリの設定、ADC_MEM0から31まであり、個々のモードを設定する。ここでモードはリピートかシングルかのモード。リピート取得するならtrueで1回だけならfalse

MAP_ADC14_configureConversionMemory:

AD変換に使うメモリの設定をする。どのピンの入力結果を変換してどこに格納するかを設定するので、使うピンの数だけ設定をすることになる。

ADC_MEM0:どこのメモリーを使うかを指定。

ADC_VREFPOS_INTBUF_VREFNEG_VSS :ADCのリファレンス電圧の指定。

VREFPOS(ポジティブ)がINTBUF(内部)でVREFNEG(ネガティブ)はVSS(GND)をリファレンスにしますよという意味。先に指定していたREF_A_setReferenceVoltageで指定されたVrefの値を基準にADCをする。

ADC_VREFPOS_AVCC_VREFNEG_VSSってのもあって、AVCC=3.3VでのADCになる。

ADC_INPUT_A0:どこのチャンネルを使うかを設定。ピン配置の図を見て決める。A0は5.5で、A1は5.4、A6は4.7・・・などなど

false:differntialMode、2つのチャンネルを使って差動入力での測定ならtrueを入れて、GNDとの差を見るならfalseを入れる。ADC_NONDIFFERENTIAL_INPUTS、ADC_DIFFERENTIAL_INPUTSとタイプしても同じ。

【特定のADCチャンネルインターラプトの許可】

    /* Enabling the interrupt when a conversion on channel 7 (end of sequence)

     *  is complete and enabling conversions */

    MAP_ADC14_enableInterrupt(ADC_INT7);

8チャンネル分のADCを読むが、順番が最後の7チャンネルのADCを監視し、変化したら割り込みサービスルーチンに飛ぶように設定する。

【ADCのインターラプトの許可】

    /* Enabling Interrupts */

    MAP_Interrupt_enableInterrupt(INT_ADC14);

    MAP_Interrupt_enableMaster();

ここはADCのコマンドというより、ADC14によるインターラプトそのものを許可して監視するようにするということ。インターラプトを検出したら処理するとう流れ。

【読み取りのタイミング設定】

/* Configuring Sample Timer */ MAP_ADC14_enableSampleTimer(ADC_AUTOMATIC_ITERATION );

ADC_AUTOMATIC_ITERATION は次々に一つ読めば次をと続けて読む。 ADC_MANUAL_ITERATIONADC_MANUAL_ITERATION:ユーザーがADC14_toggleConversionTrigger を引いて読むタイミングを決める。


 【ADCの開始】

/* Triggering the start of the sample */

    MAP_ADC14_enableConversion();

    MAP_ADC14_toggleConversionTrigger();

ここは読んで字のごとく、変換を許可して、トリガーを引く。


【インターラプト後の処理】

 /* This interrupt is fired whenever a conversion is completed and placed in

 * ADC_MEM7. This signals the end of conversion and the results array is

 * grabbed and placed in resultsBuffer */

void ADC14_IRQHandler(void)

{

    uint64_t status;

    status = MAP_ADC14_getEnabledInterruptStatus();

    MAP_ADC14_clearInterruptFlag(status);

    if(status & ADC_INT7)

    {

        MAP_ADC14_getMultiSequenceResult(resultsBuffer);

    }

}

ADC_MEM7にADCが完了した時に、インターラプトでここの処理に飛んでくる。

MAP_ADC14_getEnabledInterruptStatus:

ADCのインターラプトレジスタのステータスを返してくる。MEM0に変換後に格納が完了したらstatusには”ADC_INT0”がかえってくる。

MAP_ADC14_clearInterruptFlag:

ADCインターラプトのクリア。ここに飛んできているということは、ADC_INTのフラグが立っているので次にそなえてクリアーして元に戻してあげる。

   if(status & ADC_INT7)

の部分で、status と 8個の最後にあたるADC_INT7のアンドがとれたら、MAP_ADC14_getMultiSequenceResultで結果を配列に格納する。

ここまでをだいたいイメージで解釈できたら他のExampleのソースコードが何しているかは読めるようになった・・・



コメント

このブログの人気の投稿

Attiny85とAQM0802A(LCD)のI2C接続

ILI9341 240X320 Arduino

Attiny85 FuseRest