概要
8BitPICシリーズには入力信号を計測するSMTモジュールが搭載されているマイコンがあります。
似たような機能を持つモジュールはインプットキャプチャがありますが、SMTはより高機能に信号を計測可能です。
今回は「PIC18F57Q43」のSMTモジュールを使用します。
SMTとはSignal Measurement Timerの略で信号を測定するモジュールの事。
外部信号の周期や幅、デューティー比やエッジ時間差などを11のモードによって計測します。
更新履歴
| 更公開/変更日 | 更新内容 |
| 2022.08.16 | 初版公開 |
| 2025.04.13 | タイトル修正、リンク追加、カテゴリ変更 |
関連リンク
| 記事 | リンク | |
| 第1回 | 8bitPICシリーズ① PRGモジュールの使い方 | 8bitPICシリーズ①PRGモジュールの使い方 – ぴくおの電子工作的な何かWP |
| 第2回 | 8bitPICシリーズ② PWMモジュールの使い方 | 8bitPICシリーズ②PWMモジュールの使い方 – ぴくおの電子工作的な何かWP |
| 第3回 | 8bitPICシリーズ③ SMTモジュールの使い方 | 8bitPICシリーズ③SMTモジュールの使い方 – ぴくおの電子工作的な何かWP |
| 第4回 | 8bitPICシリーズ④ Timerモジュールの使い方 | 8bitPICシリーズ④Timerモジュールの使い方 – ぴくおの電子工作的な何かWP |
| 第5回 | 8bitPICシリーズ⑤ Angular Timer モジュールの使い方 | 8bitPICシリーズ⑤Angular Timer モジュールの使い方 – ぴくおの電子工作的な何かWP |
| 第6回 | 8bitPICシリーズ⑥ CLB(Configurable Logic Block)モジュールの使い方 | 8bitPICシリーズ⑥CLB(Configurable Logic Block)モジュールの使い方 – ぴくおの電子工作的な何かWP |
| 第7回 | ||
| 第8回 | ||
| 第9回 | ||
| 第10回 |
ハードウェア構成と制御ブロック
SMTは下記のようにクロックソースをカウントするSMTxTMRとSMT_Window入力、SMT_Signal入力、コントロールロジックなどによって構成されます。

タイマーモード
SMT_windowやSMT_signal入力は使用せず、SMTxENとSMTxGOがアクティブになった後にSMTxClockによりSMTxTMRがカウントアップしSMTxPRと一致した時に割り込み(SMTxIF)を発生させます。

ゲートタイマーモード
SMT_signalのHigh時間を測定します。
SMT_window入力は使用せずSMT_signal入力を使用します。SMT_signalがHighになった2クロックの立ち上がり信号でSMTx_signalsyncがアクティブになります。その1クロック後からSMTxClockによりSMTxTMRがカウントアップし、SMT_signalの立下りから3クロック後のSMTxTMR値がSMTxCPWにコピーされます。

周期&デューティ計測モード
SMT_signalの周期とDutyを測定します。
SMT_window入力は使用せずSMT_signal入力を使用します。SMT_signalがHighになった2クロックの立ち上がり信号でSMTx_signalsyncがアクティブになります。その1クロック後からSMTxClockによりSMTxTMRがカウントアップし、SMT_signalの立下りから3クロック後のSMTxTMRの値がSMTxCPWにコピーされます。また次のSMTx_signalsyncがアクティブになった時のSMTxTMR値をSMTxCPRにコピーされ、SMTxTMRの値は1にセットされます。

ハイ&ロー時間計測モード
SMT_signalのHigh時間とLow時間を測定します。
SMT_window入力は使用せずSMT_signal入力を使用します。SMT_signalがHighになった2クロックの立ち上がり信号でSMTx_signalsyncがアクティブになります。その1クロック後からSMTxClockによりSMTxTMRがカウントアップし、SMT_signalの立下りから3クロック後のSMTxTMR値がSMTxCPWにコピーされ、SMTxTMRの値は1にセットされます。また次のSMTx_signalsyncがアクティブになった時のSMTxTMR値がSMTxCPRにコピーされ、SMTxTMRの値は再度1にセットされます。

ウィンドウ計測モード
SMT_windowの周期時間を測定します。
SMT_signal入力は使用せずSMT_window入力を使用します。SMT_windowがHighになった2クロックの立ち上がり信号でSMTx_WINsyncがアクティブになります。その1クロック後からSMTxClockによりSMTxTMRがカウントアップし、次のSMTx_syncがアクティブになった時のSMTxTMR値がSMTxCPRにコピーされ、SMTxTMRの値は再度1にセットされます。

ゲートウィンドウ計測モード
SMT_windowの周期期間中のSMT_signalのHigh時間を測定します。
SMT_signal入力とSMT_window入力を使用します。SMT_windowがHighになった2クロックの立ち上がり信号でSMTx_WINsyncがアクティブになります。その後SMT_signalがHighになった2クロックの立ち上がり信号でSMTx_signalsyncがアクティブになります。その1クロック後からSMTx_signalsyncがアクティブの期間SMTxClockによりSMTxTMRがカウントアップします。次のSSMTx_WINsyncがアクティブになった時のSMTxTMR値がSMTxCPRにコピーされ、SMTxTMRの値は再度0にセットされます。

タイムオブフライト計測モード
SMT_windowの立ち上がりからSMT_signalの立ち上がりの時間を計測します。
SMT_signal入力とSMT_window入力を使用します。SMTx_WINsyncがアクティブになった後にSMTxTMRの値が1にセットされます。またSMTxClockによりSMTxTMRがカウントアップし、SMTx_signalsyncがアクティブになった時の値がSMTxCPRにコピーされます。その後SMTx_WINsyncがアクティブになるまでのSMTx_signalsyncは無視されます。
SMTx_WINsyncがアクティブになった後にSMTx_signalsyncがアクティブにならなかった場合、SMTxTMRの値(=SMTx_WINsyncの周期値)がSMTxCPWにコピーされます。

キャプチャーモード
SMT_windowの立ち上がりとSMT_windowの立ち下がり時間をキャプチャします。
SMT_signal入力は使用せずSMT_window入力を使用します。SMTxGO_syncがアクティブになった後からSMTxClockによりSMTxTMRがカウントアップします。SMT_windowがHighになった2クロック後にSMTx_WINsyncがアクティブになり、その時のSMTxTMRの値がSMTxCPRにコピーされます。またSMTx_WINsyncがインアクティブになったタイミングSMTxTMRの値がSMTxCPWにコピーされます。

カウンターモード
SMT_windowの周期期間中のSMT_signalの立ち上がりエッジ数をカウントします。
SMT_signal入力とSMT_window入力を使用します。SMTxGOがアクティブになった後からSMT_signalの立ち上がりエッジによりSMTxTMRがカウントアップします。その後SMT_WINの立ち上がりエッジから2クロック後のSMTxTMRの値がSMTxCPWにコピーされます。

ゲートカウンターモード
SMT_windowがアクティブ期間中に入力されたのSMT_signalの立ち上がりエッジ数をカウントします。
SMT_signal入力とSMT_window入力を使用します。SMTxGOがアクティブになった後からSMT_windowがアクティブ期間中にSMT_signalの立ち上がりエッジが入力されるとSMTxTMRがカウントアップします。その後SMT_WINの立ち上がりエッジから2クロック後のSMTxTMRの値がSMTxCPWにコピーされます。

ウィンドウカウンターモード
SMT_windowがアクティブ期間中に入力されたのSMT_signalの立ち上がりエッジ数とSMT_windowの周期期間中のSMT_signalの立ち上がりエッジ数をカウントします。
SMT_signal入力とSMT_window入力を使用します。SMTxGOがアクティブになった後にSMT_windowの立ち上がりエッジでSMTxTMRの値がSMTxCPWにコピーされ、SMTxTMRの値が1にセットされます。その後SMT_signalの立ち上がりエッジが入力されるとSMTxTMRがカウントアップされ、SMT_WINの立下りによってSMTxTMRの値がSMTxCPRにコピーされます。

ハードウェア構成
SMTの動作確認としてPWM1のP1とP2出力の立ち上がり位相差をTOFモードで計測します。

PWMの開始からP1は 0x27F – 0x140 のタイミングで立ち上がり、P2 は0x27F – 0x020 のタイミングで立ち上がります。つまり位相差は0x140 – 0x020 = 288となります。

ソースコード
ソースコードは以下の通りです。
#include "xc.h"
#pragma config FEXTOSC = ECH
#pragma config RSTOSC = EXTOSC
//CONFIG2
#pragma config CLKOUTEN = OFF
#pragma config FCMEN = ON
#pragma config CSWEN = ON
#pragma config PR1WAY = ON
//CONFIG3
#pragma config MVECEN = OFF
#pragma config MCLRE = EXTMCLR
#pragma config BOREN = SBORDIS
#pragma config PWRTS = PWRT_OFF
#pragma config IVT1WAY = ON
#pragma config LPBOREN = OFF
//CONFIG4
#pragma config XINST = OFF
#pragma config LVP = ON
#pragma config ZCD = OFF
#pragma config STVREN = ON
#pragma config BORV = VBOR_1P9
#pragma config PPS1WAY = ON
//CONFIG5
#pragma config WDTCPS = WDTCPS_31
#pragma config WDTE = OFF
//CONFIG6
#pragma config WDTCWS = WDTCWS_7
#pragma config WDTCCS = SC
//CONFIG7
#pragma config SAFEN = OFF
#pragma config BBEN = OFF
#pragma config BBSIZE = BBSIZE_512
#pragma config DEBUG = OFF
//CONFIG8
#pragma config WRTB = OFF
#pragma config WRTC = OFF
#pragma config WRTD = OFF
#pragma config WRTAPP = OFF
#pragma config WRTSAF = OFF
//CONFIG10
#pragma config CP = OFF // Background Debugger->Background Debugger disabled
int main(void)
{
volatile long Phase;
/*----------------------------------------------------------------------------*/
/* オシレータ設定 */
/*----------------------------------------------------------------------------*/
OSCCON1 = 0x60;
OSCCON3 = 0x0;
OSCEN = 0x0;
OSCFRQ = 0x8;
OSCTUNE = 0x0;
ACTCON = 0x0;
/*----------------------------------------------------------------------------*/
/* ピン設定*/
/*----------------------------------------------------------------------------*/
TRISF = 0x3C;
RF0PPS = 0x18; //RF0->PWM1_16BIT:PWM11;
RF1PPS = 0x19; //RF1->PWM1_16BIT:PWM12;
/*----------------------------------------------------------------------------*/
/* SMT設定 */
/*----------------------------------------------------------------------------*/
SMT1CON0 = 0x80;
SMT1CON1 = 0x46;
SMT1CON1bits.MODE = 6;
SMT1CON1bits.REPEAT = 1;
SMT1CLK = 0x1;
SMT1STAT = 0x0;
SMT1WIN = 0x12;
SMT1SIG = 0x11;
SMT1PRU = 0x0;
SMT1PRH = 0x0;
SMT1PRL = 0x0;
/*----------------------------------------------------------------------------*/
/* PWM設定 */
/*----------------------------------------------------------------------------*/
PWM1ERS = 0x0;
PWM1CLK = 0x2; //CLOCK = FOC
PWM1LDS = 0x0;
PWM1PRL = 0x7F; //周期下位8Bit
PWM1PRH = 0x2; //周期上位8Bit
PWM1CPRE = 0x0;
PWM1PIPOS = 0x0;
PWM1GIR = 0x0;
PWM1GIE = 0x0;
PWM1S1CFG = 0x1;
PWM1S1P1L = 0x40; //P1下位8Bit
PWM1S1P1H = 0x1; //P1上位8Bit
PWM1S1P2L = 0x20; //P2下位8Bit
PWM1S1P2H = 0x0; //P2上位8Bit
PIR4bits.PWM1PIF = 0;
PIR4bits.PWM1IF = 0;
PWM1GIRbits.S1P1IF = 0;
PWM1GIRbits.S1P2IF = 0;
PIE4bits.PWM1IE = 0;
PIE4bits.PWM1PIE = 0;
PWM1CON = 0x80;
SMT1CON1bits.SMT1GO = 1u;
while(1)
{
while(PIR1bits.SMT1PRAIF == 0){;}
PIR1bits.SMT1PRAIF = 0;
Phase= SMT1CPR;
Nop();
}
}
結果
PIR1bits.SMT1PRAIFがセットされた後にSMT1CPRの値をPhaseにコピーし確認すると、想定通り288の値が取得できています。



コメント