2

したがって、この質問は一種の「続編」です: Stm32f4: DMA + ADC Transfer pausing

繰り返しますが、私はそのようなアルゴリズムを実装しようとしています:

  1. 1 つのチャネルでトリプル インターリーブ モードの ADC を使用して DMA を初期化する
  2. 外部割り込み待ち
  3. DMA転送とADCをサスペンド
  4. 割り込みでUSARTを介してメモリからバッファリングされたデータを送信します
  5. DMA と ADC を再開する
  6. 割り込みを終了し、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);
}
4

1 に答える 1

2

私は自分で解決策を見つけました。DMA の問題だと思っていました。しかし、それは ADC の問題であることが判明しました。ADCx->CR レジスタの OVR フラグは、転送が「スタック」したときに常にセットされていました。そこで、ADC オーバーランの状況に割り込みを追加し、その中で DMA と ADC を再起動しました。問題は解決しました。

于 2016-12-14T15:51:51.280 に答える