前々回、Arduino Uno R4搭載RA4M1マイコンの周辺回路レジスタへの直接アクセスを練習。今回はその応用編ということで、RA4M1マイコン搭載のアナログ・コンパレータを使ってみたいと思います。割り込み受けするのが普通だと思いますが、今回は「おためし」ということで直接外部出力、兼、ソフトでポーリングしてみます。
※「やっつけな日常」投稿順 Index はこちら
RA4M1のアナログコンパレータ
Uno R4搭載のRA4M1(型番的にはR7FA4M1AB3CFM)は、2チャンネルのアナログ・コンパレータをチップ上に集積しています。これはオンチップのオペアンプ4個とは別です。2チャンネルといいつつ、各チャンネルは単独コンパレータの動作モード以外に上下2つのコンパレータに相当するウインドウモードももっているのでコンパレータ4個相当ともいえるかもです。
さてArduino Uno R4のボード配線上これらが使えるか否かですが、調べてみたところでは端子的な制限はあるものの、2チャンネルとも使える、と考えます。今回は、「0」と「1」の2個あるうちの「1」の方をアナログコンパレータとして使ってみたいと思います。端子的には以下のようになります。
Arduino端子名 | チップ端子名 | コンパレータ端子機能 |
---|---|---|
D4 | P103 | CMPREF1 |
D5 | P102 | CMPIN1 |
D12 | P110 | VCOUT |
D4の参照電圧をD5の入力電圧が上回ったらD12にハイが出力されるような設定としてみました。今回は実験のためD4に外部参照電圧を与えていますが、内蔵の参照電圧(DAC出力を参照することも可能)を使えば外部電圧不要です。また、コンパレートした結果は割り込みやイベント受けで制御のトリガに使うということであれば外部出力も不要だと思います。入力端子1本で所望の電圧の上か下か判断できます。
なお「ウインドウモード」を使えばある電圧「範囲内」、とか「範囲外」という判定も可能です(当然、上下2種類の参照電圧必要。)今回はメンドイのでやってません。手抜きだな。
アナログコンパレータ設定用の関数
みた感じArduinoのAPIにはアナログコンパレータ設定用の関数が用意されていないようだったので、前々回のお作法にしたがって、「キメウチの値で」アナログコンパレータを初期化する関数を作ってみました。こんな感じ。
void initACMPLP1() { (R_MSTP->MSTPCRD_b.MSTPD29) = 0; //クロック供給 (R_PFS->PORT[1].PIN[2].PmnPFS_b.ASEL) = 1; //P102...Analog input D5 (R_PFS->PORT[1].PIN[3].PmnPFS_b.ASEL) = 1; //P103...Analog input D4 (R_ACMPLP->COMPSEL0_b.IVCMP0) = 0x0; // CMPIN0...No input (R_ACMPLP->COMPSEL0_b.IVCMP1) = 0x1; // CMPIN1...P102 (R_ACMPLP->COMPSEL1_b.IVREF0) = 0x0; // CMPREF0...Disable (R_ACMPLP->COMPSEL1_b.IVREF1) = 0x0; // CMPREF1...Disable (R_ACMPLP->COMPSEL1_b.C1VRF2) = 1; // ACMPLP1 REF voltage...Select IVREF1 (R_ACMPLP->COMPSEL1_b.IVREF0) = 0x0; // CMPREF0...No input (R_ACMPLP->COMPSEL1_b.IVREF1) = 0x1; // CMPREF1...P103 (R_ACMPLP->COMPOCR_b.SPDMD) = 0; // Low speed mode (R_ACMPLP->COMPMDR_b.C1WDE) = 0; // Window mode disable (R_ACMPLP->COMPMDR_b.C1VRF) = 0; // External reference voltage (R_ACMPLP->COMPMDR_b.C1ENB) = 1; // ACMPLP1 Enable delayMicroseconds(100); // wait 100 usec (R_ACMPLP->COMPFIR_b.C1FCK) = 0x0; // Bypass filter (R_ACMPLP->COMPOCR_b.C1OP) = 0x0; // Normal (R_ACMPLP->COMPOCR_b.C1OE) = 0x1; // Enable VCOUT (R_PFS->PORT[1].PIN[10].PmnPFS_b.PSEL) = 0x9; // P110...select VCOUT (R_PFS->PORT[1].PIN[10].PmnPFS_b.PMR) = 1; // P110...Peripheral output }
上記は1個1個ビットフィールド操作で設定値を設定していてまどろっこしいです。パラレルアクセスで複数ビットを一度に設定した方が手っとりばやいケースありですが、前々回のお作法の練習用にベタ書きしてます。
また、後々の応用考えたら、Class定義にした方が綺麗な気がしますが、ベタ書きです。実験用ね。
本体部分
上記の設定関数 initACMPLP1() を呼び出せば、アナログコンパレータ「1」が前述の端子の上で「低速モード」(遅延時間が5μsecくらいと遅くなるけれども消費電力は小さい「2μA」らしいデス)で動作します。本体部分では「いつものLチカ」をやりながら、ACMPLP1のモニタビットをソフトウエアでポーリングして判定結果をシリアルポートにprintしてます。本体コードは以下です。
void setup() { Serial.begin(9600); while (!Serial) { } pinMode(13, OUTPUT); // Pin13(D13) = P111 (Port 1 pin 11) initACMPLP1(); } void loop() { Serial.print("Analog Comparator 1 (low power mode)\n"); digitalWrite(13, HIGH); Serial.print("ACMPLP1 Monitor="); Serial.println(R_ACMPLP->COMPMDR_b.C1MON); delay(333); digitalWrite(13, LOW); Serial.print("ACMPLP1 Monitor="); Serial.println(R_ACMPLP->COMPMDR_b.C1MON); delay(333); }
実機動作結果
黄色C1が、CMPIN1に与えた三角波で、青色C2がVCOUT出力です。VREFはDCで朧げな記憶によれば2Vくらいだった筈。いい加減な。
なお、USBシリアルへもソフトウエアポーリングの結果をたれ流しているので、その様子が以下に。時々 Monitor=1だったりMonitor=0だったりしてます。
まあ、アナログ・コンパレータ、使えるみたい。いい加減だけど。