STM32 DMA问题

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了STM32 DMA问题相关的知识,希望对你有一定的参考价值。

我有3个外设需要DMA一个DAC,一个串口,一个ADC。问这3个DMA会冲突吗?能够同时工作不... 我有3个外设需要DMA一个DAC,一个串口,一个ADC。问这3个DMA会冲突吗?能够同时工作不 展开

参考技术A STM32的DMA有多路!例如F103zet6有DMA1
7路
DMA2
5路,共计12路DMA通道。
使用三个不同外设分别配置三个通道即可!要注意每个外设对应的通道是手册中固定的,不能自己定义。同时避开冲突的外设即可。
举例:ADC1,TIM2_CH3,TIM4_CH1三个外设通道可配置为DMA1_CH1
。使用此三个外设时必须配置为此通道,且此三个外设不可同时使能配置使用!

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

【中文标题】stm32f4 DMA 在挂起后并不总是启动【英文标题】:stm32f4 DMA does not always start after suspending 【发布时间】:2017-04-28 21:09:20 【问题描述】:

所以这个问题是这个问题的“续集”:Stm32f4: DMA + ADC Transfer pausing。

再次,我正在尝试实现这样的算法:

    在一个通道上以三重交错模式使用 ADC 初始化 DMA 等待外部中断 暂停 DMA 传输和 ADC 在中断中通过USART从内存中发送缓冲数据 恢复 DMA 和 ADC 退出中断,转到 2。

DMA 和 ADC 暂停和恢复,但有时(在大约 16% 的中断调用中)恢复失败 - DMA 只是从 ADC 写入第一个测量值并停止直到下一个中​​断,其中 DMA 和 ADC 重新启动(因为它们被暂停并再次恢复)并且 - 好吧,一切都会恢复正常,直到下一个此类错误。

我试过暂停 DMA,就像参考手册说的那样:

为了从传输停止的点重新开始, 软件必须在禁用后读取 DMA_SxNDTR 寄存器 通过在 DMA_SxCR 寄存器中写入 EN 位(然后检查 它是'0')知道已经收集的数据项的数量。 然后: – 必须更新外设和/或内存地址以调整地址指针 – 必须使用要传输的剩余数据项数(流被禁用时读取的值)更新 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);

【问题讨论】:

【参考方案1】:

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

【讨论】:

只需添加一个类似的问题,但使用 usart。如果您不关心溢出/错误检测,那么通常会有一个标志来禁用此行为。希望 DMA 章节能更明确地说明什么可能导致它“停止工作”。此外,您应该选择您的答案作为正确答案。 @Lesto 我不记得在 ADC 的情况下是否有禁用此行为的标志,但我确实记得仅重置标志并没有太大作用 - 我确实必须重新启动两个 DMA和 ADC,所以,也许,你也不应该忽略这个标志并重新启动 USART? @Lesto 我确实希望 STM 程序手册在所有方面都更加明确

以上是关于STM32 DMA问题的主要内容,如果未能解决你的问题,请参考以下文章

STM32Cube 串口DMA发送问题

STM32F0 DMA“输入溢出”

STM32 ADC 多通道 DMA 问题??

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

stm32dma填入的内容怎么修改

stm32dma串口没有收到包头