MSP432 ADC
はじめの例題として、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();
【読み取りのタイミング設定】
/* 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が完了した時に、インターラプトでここの処理に飛んでくる。
ADCのインターラプトレジスタのステータスを返してくる。MEM0に変換後に格納が完了したらstatusには”ADC_INT0”がかえってくる。
MAP_ADC14_clearInterruptFlag:
ADCインターラプトのクリア。ここに飛んできているということは、ADC_INTのフラグが立っているので次にそなえてクリアーして元に戻してあげる。
if(status & ADC_INT7)
の部分で、status と 8個の最後にあたるADC_INT7のアンドがとれたら、MAP_ADC14_getMultiSequenceResultで結果を配列に格納する。
ここまでをだいたいイメージで解釈できたら他のExampleのソースコードが何しているかは読めるようになった・・・
コメント
コメントを投稿