stm32f4 DMA在挂起后并不总是启动

stm32f4 DMA在挂起后并不总是启动,stm32,dma,stm32f4discovery,stm32f4,Stm32,Dma,Stm32f4discovery,Stm32f4,所以这个问题是这个问题的“续集”: 我再次尝试实现这样一种算法: 在一个通道上以三重交织模式使用ADC初始化DMA 等待外部中断 暂停DMA传输和ADC 在中断中通过USART从内存发送缓冲数据 恢复DMA和ADC 退出中断,转到2 DMA和ADC暂停并恢复,但有时(在大约16%的中断调用中)恢复失败-DMA只是从ADC写入第一个测量值并停止,直到下一个中断,在此中断中,DMA和ADC重新启动(因为它们再次暂停并恢复),并且-嗯,在下一个这样的错误之前,一切都恢复正常 我尝试过暂停DMA,正如参

所以这个问题是这个问题的“续集”:

我再次尝试实现这样一种算法:

  • 在一个通道上以三重交织模式使用ADC初始化DMA
  • 等待外部中断
  • 暂停DMA传输和ADC
  • 在中断中通过USART从内存发送缓冲数据
  • 恢复DMA和ADC
  • 退出中断,转到2
  • DMA和ADC暂停并恢复,但有时(在大约16%的中断调用中)恢复失败-DMA只是从ADC写入第一个测量值并停止,直到下一个中断,在此中断中,DMA和ADC重新启动(因为它们再次暂停并恢复),并且-嗯,在下一个这样的错误之前,一切都恢复正常

    我尝试过暂停DMA,正如参考手册所说:

    为了从停止传输的点重新启动 禁用后,软件必须读取DMA_SxNDTR寄存器 通过将EN位写入DMA_SxCR寄存器(然后检查 知道已收集的数据项的数量是在“0”处。 然后:
    –为了调整地址指针,必须更新外围设备和/或内存地址
    –必须使用要传输的剩余数据项(流被禁用时读取的值)更新SxNDTR寄存器
    –然后可重新启用流,以从停止点重新启动传输

    唯一的实际差异是恢复DMA工作时写入的NDTR值。在我的例子中是缓冲区大小,在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);
    }
    

    我自己找到了解决办法。我认为这是一个DMA问题;然而,这变成了ADC的问题。
    ADCx->CR寄存器中的OVR标志始终在传输被“卡住”时设置。因此,我在ADC溢出情况中添加了一个中断,并在其中重新启动了DMA和ADC。问题现在解决了。

    只需添加一个类似的问题,但使用usart即可。如果您不关心oveflow/错误检测,那么通常会有一个标志来禁用此行为。希望DMA一章能更明确地说明“停止工作”的理由。您也应该选择您的答案作为正确答案。@Lesto我不记得在ADC的情况下是否有一个标志来禁用此行为,但我记得只是重置标志没有多大作用-我确实必须重新启动DMA和ADC,因此,也许,你也不应该忽略这个标志,然后重新启动USART?@Lesto我真希望STM progmanuals在每件事上都更加明确