したがって、この質問は一種の「続編」です: Stm32f4: DMA + ADC Transfer pausing。
繰り返しますが、私はそのようなアルゴリズムを実装しようとしています:
- 1 つのチャネルでトリプル インターリーブ モードの ADC を使用して DMA を初期化する
- 外部割り込み待ち
- DMA転送とADCをサスペンド
- 割り込みでUSARTを介してメモリからバッファリングされたデータを送信します
- DMA と ADC を再開する
- 割り込みを終了し、2 に進みます。
DMA と ADC は一時停止して再開しますが、(割り込み呼び出しの約 16% で) 再開に失敗することがあります。再び再開) そして - さて、次のそのようなバグまで、すべてが正常に戻ります。
リファレンス マニュアルにあるように、DMA を一時停止してみました。
転送が停止したポイントから再開するには、ソフトウェアは、DMA_SxCR レジスタに EN ビットを書き込んでストリームを無効にした後 (次に、EN ビットが「0」であることを確認)、DMA_SxNDTR レジスタを読み取って、転送の数を知る必要があります。収集済みのデータ項目。次に、 –
アドレス ポインタを調整するために、ペリフェラルおよび/またはメモリ アドレスを更新する必要があります
– SxNDTR レジスタを、転送するデータ項目の残りの数で更新する必要があります (ストリームが無効になったときに読み取られた値)
–その後、ストリームを再度有効にして、停止した時点から転送を再開することができます
唯一の実際の違いは、DMA の動作を再開する際に書き込まれる NDTR 値にあります。私の場合は buffer_size です。RefMan の場合は、DMA の一時停止中に読み取られた値です。RefMan の場合、一時停止後に DMA が再び開始されることはありません。私の場合、上で述べたように、開始しますが、常にではありません。
どうすればこれを防ぐことができますか?
現在、割り込みコードは次のようになっています。
void EXTI4_IRQHandler(void) {
uint16_t temp = DMA_GetFlagStatus(DMA2_Stream0, DMA_FLAG_TEIF0);
if(EXTI_GetITStatus(EXTI_Line4) != RESET) {
uint16_t fPoint1 = 0;
uint16_t fPoint2 = 0;
//Some delay using the TIM2
TIM_SetCounter(TIM2, 0);
TIM_Cmd(TIM2, ENABLE);
//Measure the first point NDTR
fPoint1 = DMA2_Stream0->NDTR;
while(TIM_GetITStatus(TIM2, TIM_IT_Update) != SET) {};
//Measure the second point here.
fPoint2 = DMA2_Stream0->NDTR;
if(fPoint1 == fPoint2) {
//The NDTR does not change!
//If it does not change, it is stuck at buffer_size - 1
}
//Disable the timer
TIM_ClearITPendingBit(TIM2, TIM_IT_Update);
TIM_Cmd(TIM2, DISABLE);
DMA_Cmd(DMA2_Stream0, DISABLE);
//Wait until the DMA will turn off
while((DMA2_Stream0->CR & (uint32_t)DMA_SxCR_EN) != 0x00) {};
//Turn off all ADCs
ADC_Cmd(ADC1, DISABLE);
ADC_Cmd(ADC2, DISABLE);
ADC_Cmd(ADC3, DISABLE);
//Send all the data here
//Turn everything back on
//Turn the DMA ON again
DMA_SetCurrDataCounter(DMA2_Stream0, BUFFERSIZE);
DMA_Cmd(DMA2_Stream0, ENABLE);
while((DMA2_Stream0->CR & (uint32_t)DMA_SxCR_EN) == 0x00) {};
//See note @ RefMan (Rev. 12), p. 410
ADC->CCR &= ~((uint32_t)(0x000000FF));
ADC->CCR |= ADC_TripleMode_Interl;
ADC_Cmd(ADC1, ENABLE);
ADC_Cmd(ADC2, ENABLE);
ADC_Cmd(ADC3, ENABLE);
while((ADC1->CR2 & (uint32_t)ADC_CR2_ADON) == 0) {};
while((ADC2->CR2 & (uint32_t)ADC_CR2_ADON) == 0) {};
while((ADC3->CR2 & (uint32_t)ADC_CR2_ADON) == 0) {};
ADC_SoftwareStartConv(ADC1);
}
EXTI_ClearITPendingBit(EXTI_Line4);
}