32 ビット カウンターの 2 つの TMR チャネルをカスケード接続すると、入力キャプチャが正常に動作しないようです。入力キャプチャは、1 つのチャネルのみを使用する場合は正常に機能しますが、チャネルをカスケードしようとすると機能しません。
1.TMR1 ch0 および ch1 構造が定義されています。TMR1 ch0のクロックソースはkQTMR_ClockDivide_1、TMR2 ch1のクロックソースはkQTMR_ClockCounter0Outputです。
2. qtmr_begin はチャネルを初期化します。フリーランニングに設定されています。TMR1 IRQが有効です。入力キャプチャに対して TMR1 割り込みが有効になります。タイマーが開始されます。
getCount を呼び出すと、上位カウント (チャネル 1) に対して 0 のみが返されます。それ以外の場合、上位カウントを無視すると、下位カウントは常に正しいものになります。
const qtmr_config_t QuadTimer_1_Channel_0_config = {
.primarySource = kQTMR_ClockDivide_1,
.secondarySource = kQTMR_Counter0InputPin,
.enableMasterMode = false,
.enableExternalForce = false,
.faultFilterCount = 0,
.faultFilterPeriod = 0,
.debugMode = kQTMR_RunNormalInDebug
};
const qtmr_config_t QuadTimer_1_Channel_1_config = {
.primarySource = kQTMR_ClockCounter0Output,
.secondarySource = kQTMR_Counter0InputPin,
.enableMasterMode = false,
.enableExternalForce = false,
.faultFilterCount = 0,
.faultFilterPeriod = 0,
.debugMode = kQTMR_RunNormalInDebug
};
void qtmr_begin()
{
QTMR_Init(TMR1, kQTMR_Channel_0, &QuadTimer_1_Channel_0_config);
QTMR_Init(TMR1, kQTMR_Channel_1, &QuadTimer_1_Channel_1_config);
/* Ensure free-running (no stop at compare) */
TMR1->CHANNEL[kQTMR_Channel_0].CTRL &= ~TMR_CTRL_LENGTH_MASK;
TMR1->CHANNEL[kQTMR_Channel_1].CTRL &= ~TMR_CTRL_LENGTH_MASK;
/* Setup the input capture */
QTMR_SetupInputCapture(TMR1, kQTMR_Channel_0, QTMR_CounterInputPin, false, true, kQTMR_RisingEdge);
/* Enable at the NVIC */
EnableIRQ(TMR1_IRQn);
/* Enable timer compare interrupt */
QTMR_EnableInterrupts(TMR1, kQTMR_Channel_0, kQTMR_EdgeInterruptEnable);
QTMR_StartTimer(TMR1, kQTMR_Channel_0, kQTMR_PriSrcRiseEdge);
QTMR_StartTimer(TMR1, kQTMR_Channel_1, kQTMR_CascadeCount);
}
void TMR1_IRQHandler(void)
{
QTMR_ClearStatusFlags(TMR1, kQTMR_Channel_0, kQTMR_EdgeFlag);
qtmrIsrFlag = true;
}
void getCount(void)
{
// Discard the first capture
for (int i = 0; i < 2; i++)
{
while (!qtmrIsrFlag)
{
}
qtmrIsrFlag = false;
uint16_t lowerCount = TMR1->CHANNEL[kQTMR_Channel_0].CAPT;
uint16_t upperCount = TMR1->CHANNEL[kQTMR_Channel_1].HOLD;
uint32_t counterValue = ((uint32_t)upperCount << 16) | lowerCount;
}
}私はこれをある程度理解しました。上位 (チャネル 1) のカウントを読み取るために間違ったレジスタを使用していました。HOLD レジスタは、カスケード チャネルのカウントを保持するのではなく、ハードウェアまたはソフトウェアの特定のイベント中にカウンター値を保存するために使用されます。通常は、イベントを同期したり、以前の値を保持したりするために使用されます。
単に CNTR レジスタを読み取る必要があります。IRQ ハンドラーですぐに読み取ることも、直後に読み取ることもでき、下位 16 ビットに同期されます。
しかし、私が理解できない別の問題が見つかりました。チャネル 1 のタイマーを 0 にリセットすると、カウントは常に 0 ではなく 1 から開始されます。SO、キャプチャされた時間は、(チャネル 1) の上位カウントで常に 1 ずれます。これを補うために、正しいカウントを取得するには、チャネル 1 のカウンターを 0xFFFF にリセットする必要があります。なぜ?
const qtmr_config_t QuadTimer_1_Channel_0_config = {
.primarySource = kQTMR_ClockDivide_1,
.secondarySource = kQTMR_Counter0InputPin,
.enableMasterMode = false,
.enableExternalForce = false,
.faultFilterCount = 0,
.faultFilterPeriod = 0,
.debugMode = kQTMR_RunNormalInDebug
};
const qtmr_config_t QuadTimer_1_Channel_1_config = {
.primarySource = kQTMR_ClockCounter0Output,
.secondarySource = kQTMR_Counter0InputPin,
.enableMasterMode = false,
.enableExternalForce = false,
.faultFilterCount = 0,
.faultFilterPeriod = 0,
.debugMode = kQTMR_RunNormalInDebug
};
void qtmr_begin()
{
QTMR_Init(TMR1, kQTMR_Channel_0, &QuadTimer_1_Channel_0_config);
QTMR_Init(TMR1, kQTMR_Channel_1, &QuadTimer_1_Channel_1_config);
/* Ensure free-running (no stop at compare) */
TMR1->CHANNEL[kQTMR_Channel_0].CTRL &= ~TMR_CTRL_LENGTH_MASK;
TMR1->CHANNEL[kQTMR_Channel_1].CTRL &= ~TMR_CTRL_LENGTH_MASK;
/* Setup the input capture */
QTMR_SetupInputCapture(TMR1, kQTMR_Channel_0, QTMR_CounterInputPin, false, true, kQTMR_RisingEdge);
/* Enable at the NVIC */
EnableIRQ(TMR1_IRQn);
/* Enable timer compare interrupt */
QTMR_EnableInterrupts(TMR1, kQTMR_Channel_0, kQTMR_EdgeInterruptEnable);
QTMR_StartTimer(TMR1, kQTMR_Channel_1, kQTMR_CascadeCount);
QTMR_StartTimer(TMR1, kQTMR_Channel_0, kQTMR_PriSrcRiseEdge);
}
void TMR1_IRQHandler(void)
{
QTMR_ClearStatusFlags(TMR1, kQTMR_Channel_0, kQTMR_EdgeFlag);
qtmrIsrFlag = true;
}
void getCount(void)
{
// Discard the first capture
uint16_t lowerCount;
uint16_t upperCount;
uint32_t counterValue;
for (int i = 0; i < 2; i++)
{
/* Reset channel 1 count to 0 - for some reason we have to reset to one value before or the count is off by 1...so we reset to 0xFFFF */
TMR1->CHANNEL[kQTMR_Channel_1].CNTR = 0xFFFF;
while (!qtmrIsrFlag)
{
}
qtmrIsrFlag = false;
lowerCount = TMR1->CHANNEL[kQTMR_Channel_0].CAPT;
upperCount = TMR1->CHANNEL[kQTMR_Channel_1].CNTR;
counterValue = ((uint32_t)upperCount << 16) | lowerCount;
}
}こんにちは@azone 、
弊社の製品にご興味をお持ちいただき、またコミュニティをご利用いただき誠にありがとうございます。
QTMR カスケード モードと入力キャプチャの併用に関するご質問に基づいて検証テストを行いました。
ハードウェア: MIMXRT1060‑EVKB、入力信号をJ33-6に接続します。
ソフトウェア: QTMR3 チャネル 0 とチャネル 1 をカスケード モードで構成
この設定を使用すると、カウンターがカスケードされている間も入力キャプチャは正常に機能します。
エッジ割り込みフラグが設定されている場合は、キャプチャレジスタを読み取ることができます。
mayliu1_0-1768206759574.png
BOARD_QTMR_BASEADDR->チャネル[BOARD_QTMR_INPUT_CAPTURE_CHANNEL0].CAPT;
および BOARD_QTMR_BASEADDR->チャネル[BOARD_QTMR_INPUT_CAPTURE_CHANNEL1].CAPT;
よろしくお願いいたします。
メイリュー
こんにちは。返信ありがとうございます。設定から、カスケード チャネル 1 のカウントを取得する最適な方法は、CNTR レジスタの読み取りに頼るのではなく、このチャネルの入力キャプチャも設定して CAPT レジスタを読み取ることであることがわかります。
これは機能します。しかし、チャネル 1 では依然として値が 1 つ高くカウントされます。私は SDK の API を使用しており、直接レジスタを操作しているわけではありませんが、私の設定はあなたの設定と同じようです。
何が起こるかの例として、150MHz の TMR クロックで 1kHz 信号を入力すると、150,000 というカウントが予想されます。これは、上位 16 ビットのカウントが '2'、下位 16 ビットのカウントが '18928' = 150,000 になります。ただし、上限は「3」になります。測定されたどの周波数でも常に +1 ずれます。なぜそうなるのでしょうか?
const qtmr_config_t QuadTimer_1_Channel_0_config = {
.primarySource = kQTMR_ClockDivide_1,
.secondarySource = kQTMR_Counter0InputPin,
.enableMasterMode = false,
.enableExternalForce = false,
.faultFilterCount = 0,
.faultFilterPeriod = 0,
.debugMode = kQTMR_RunNormalInDebug
};
const qtmr_config_t QuadTimer_1_Channel_1_config = {
.primarySource = kQTMR_ClockCounter0Output,
.secondarySource = kQTMR_Counter0InputPin,
.enableMasterMode = false,
.enableExternalForce = false,
.faultFilterCount = 0,
.faultFilterPeriod = 0,
.debugMode = kQTMR_RunNormalInDebug
};
void qtmr_begin()
{
CLOCK_EnableClock(kCLOCK_Timer1);
QTMR_Init(TMR1, kQTMR_Channel_0, &QuadTimer_1_Channel_0_config);
QTMR_Init(TMR1, kQTMR_Channel_1, &QuadTimer_1_Channel_1_config);
/* Explicitly disable secondary source - not supported in API and not necessary but doing it anyways */
TMR1->CHANNEL[kQTMR_Channel_0].CTRL &= ~TMR_CTRL_SCS_MASK;
TMR1->CHANNEL[kQTMR_Channel_1].CTRL &= ~TMR_CTRL_SCS_MASK;
/* Ensure free-running (no stop at compare) */
TMR1->CHANNEL[kQTMR_Channel_0].CTRL &= ~TMR_CTRL_LENGTH_MASK;
/* Setup the input capture */
QTMR_SetupInputCapture(TMR1, kQTMR_Channel_0, kQTMR_Counter0InputPin, false, true, kQTMR_RisingEdge);
QTMR_SetupInputCapture(TMR1, kQTMR_Channel_1, kQTMR_Counter0InputPin, false, true, kQTMR_RisingEdge);
/* Enable at the NVIC */
EnableIRQ(TMR1_IRQn);
/* Enable timer compare interrupt */
QTMR_EnableInterrupts(TMR1, kQTMR_Channel_0, kQTMR_EdgeInterruptEnable);
}
void TMR1_IRQHandler(void)
{
uint16_t lowerCount;
uint16_t upperCount;
QTMR_ClearStatusFlags(TMR1, kQTMR_Channel_0, kQTMR_EdgeFlag);
qtmrIsrFlag = true;
lowerCount = TMR1->CHANNEL[kQTMR_Channel_0].CAPT;
upperCount = TMR1->CHANNEL[kQTMR_Channel_1].CAPT; // UPPER COUNT IS ALWAYS OFF BY +1
}
void getCount(void)
{
uint32_t counterValue;
while (!qtmrIsrFlag)
{
}
qtmrIsrFlag = false;
counterValue = ((uint32_t)upperCount << 16) | lowerCount;
}
}こんにちは@azoneさん、
最新情報をありがとうございます。
あなたの新しい質問に関して、私もテストをしました。150MHzのTMRクロックで1kHzの信号を入力すると、正しい値が得られます。
HW: MIMXRT1060-EVKB、J33-6に1KHZ信号を入力します。
SW: 前回の投稿を参照してください。
mayliu1_2-1768290894570.png
mayliu1_1-1768290710042.png
よろしくお願いします
メイリュー
わかりました。テストしていただきありがとうございます。設定にエラーがあるはずです。ハードウェアを変更して、16 ビット QTMR の代わりに 32 ビット GPT を使用することができたので、カスケード モードを使用する必要がなくなりました。ただし、これを見るかもしれない他の人を助けるために、少し時間をかけてエラーを探し、この投稿を更新してみようと思います。