精华内容
下载资源
问答
  • 串口工作在DMA模式下有时接收异常

    千次阅读 2016-11-25 16:56:05
    1 前言客户反馈在使用STM32F205的串口工作在DMA模式时,有时能够接收数据,有时完全没有数据,但如果换成中断模式来接收又能100%正常收到数据。2 复现现象2.1 问题背景与客户沟通,客户使用的是STM32F2标准库V1.1.0...

    1 前言

    客户反馈在使用STM32F205的串口工作在DMA模式时,有时能够接收数据,有时完全没有数据,但如果换成中断模式来接收又能100%正常收到数据。

    2 复现现象

    2.1 问题背景

    与客户沟通,客户使用的是STM32F2标准库V1.1.0,串口波特率为1.408Mbps,不经过串口RS232,直接连接主CPU和从MCU(STM32F205)的串口发送和接收引脚,如下图所示:

    图1

    图1

    2.2 尝试重现问题

    由于客户使用的是主从架构,实验采用两块STM3220G-EVAL评估板来重现现象。一块用来不间断发送串口数据,另一块采用串口DMA进行接收,直接通过杜邦线连接串口PIN脚并共地,不使用评估板上的RS232收发器。接收端使用STM32F2xx_StdPeriph_Examples\ USART\USART_TwoBoards的示例代码。代码片段如下:

    int main(void)
    {
      ...
      USART_Config();
      ...
      while (1)
      {
        /* Clear Buffers */
        Fill_Buffer(RxBuffer, TXBUFFERSIZE);
        Fill_Buffer(CmdBuffer, 2);
    
        DMA_DeInit(USARTx_RX_DMA_STREAM);
        DMA_InitStructure.DMA_Channel = USARTx_RX_DMA_CHANNEL;
        DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;
        /************* USART will receive the the transaction data ****************/
        /* Transaction data (length defined by CmdBuffer[1] variable) */       
        DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)RxBuffer;
        DMA_InitStructure.DMA_BufferSize =10;// (uint16_t)CmdBuffer[1];
        DMA_InitStructure.DMA_Mode =DMA_Mode_Normal;//DMA_Mode_Circular;
        DMA_Init(USARTx_RX_DMA_STREAM, &DMA_InitStructure);
        NVIC_InitStructure.NVIC_IRQChannel = DMA1_Stream1_IRQn;
        NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
        NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
        NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
        NVIC_Init(&NVIC_InitStructure); 
        /* Enable DMA Stream Transfer Complete interrupt */
        DMA_ITConfig(USARTx_RX_DMA_STREAM, DMA_IT_TE|DMA_IT_DME|DMA_IT_FE, ENABLE);
    
        /* Enable the DMA Stream */
        DMA_Cmd(USARTx_RX_DMA_STREAM, ENABLE);
        /* Enable the USART Rx DMA requests */
        USART_DMACmd(USARTx, USART_DMAReq_Rx , ENABLE);
    
    //  USART_Cmd(USARTx, ENABLE);
    //  while(SET ==USART_GetFlagStatus(USARTx,USART_FLAG_ORE))
    //  {
    //    Tmp =USART_ReceiveData(USARTx);
    //  }
    
    
        while ((DMA_GetFlagStatus(USARTx_RX_DMA_STREAM, USARTx_RX_DMA_FLAG_TCIF) ==     RESET)
        {
        }   
        /* Clear all DMA Streams flags */
        DMA_ClearFlag(USARTx_RX_DMA_STREAM, USARTx_RX_DMA_FLAG_HTIF | USARTx_RX_DMA_FLAG_TCIF);
    
        /* Disable the DMA Stream */
        DMA_Cmd(USARTx_RX_DMA_STREAM, DISABLE);
    
        /* Disable the USART Rx DMA requests */
        USART_DMACmd(USARTx, USART_DMAReq_Rx, DISABLE);
    
    //handle the RxBuffer data...
        //...
      }
    }
    

    USART_Config()函数如下:

    static void USART_Config(void)
    {
      USART_InitTypeDef USART_InitStructure;
      GPIO_InitTypeDef GPIO_InitStructure;
    
      /* Peripheral Clock Enable -------------------------------------------------*/
      /* Enable GPIO clock */
      RCC_AHB1PeriphClockCmd(USARTx_TX_GPIO_CLK | USARTx_RX_GPIO_CLK, ENABLE);
    
      /* Enable USART clock */
      USARTx_CLK_INIT(USARTx_CLK, ENABLE);
    
      /* Enable the DMA clock */
      RCC_AHB1PeriphClockCmd(USARTx_DMAx_CLK, ENABLE);
    
      /* USARTx GPIO configuration -----------------------------------------------*/ 
      /* Connect USART pins to AF7 */
      GPIO_PinAFConfig(USARTx_TX_GPIO_PORT, USARTx_TX_SOURCE, USARTx_TX_AF);
      GPIO_PinAFConfig(USARTx_RX_GPIO_PORT, USARTx_RX_SOURCE, USARTx_RX_AF);
    
      /* Configure USART Tx and Rx as alternate function push-pull */
      GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
      GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
      GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
      GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
    
      GPIO_InitStructure.GPIO_Pin = USARTx_TX_PIN;
      GPIO_Init(USARTx_TX_GPIO_PORT, &GPIO_InitStructure);
    
      GPIO_InitStructure.GPIO_Pin = USARTx_RX_PIN;
      GPIO_Init(USARTx_RX_GPIO_PORT, &GPIO_InitStructure);
    
      /* USARTx configuration ----------------------------------------------------*/
      /* Enable the USART OverSampling by 8 */
      USART_OverSampling8Cmd(USARTx, ENABLE); 
    
      USART_InitStructure.USART_BaudRate = 1408000;//3750000;
      USART_InitStructure.USART_WordLength = USART_WordLength_8b;
      USART_InitStructure.USART_StopBits = USART_StopBits_1;
      /* When using Parity the word length must be configured to 9 bits */
      USART_InitStructure.USART_Parity = USART_Parity_No;
      USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
      USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
      USART_Init(USARTx, &USART_InitStructure);
    
      /* Configure DMA controller to manage USART TX and RX DMA request ----------*/  
      DMA_InitStructure.DMA_PeripheralBaseAddr = USARTx_DR_ADDRESS;
      DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
      DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
      DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
      DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
      DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
      DMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh;
      DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Enable;
      DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_Full;
      DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;
      DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
      /* Here only the unchanged parameters of the DMA initialization structure are
         configured. During the program operation, the DMA will be configured with 
         different parameters according to the operation phase */
    
      /* Enable USART */
      USART_Cmd(USARTx, ENABLE);
    }
    

    按如上代码,有如下现象:
    1. 代码不做修改,若先启动接收端MCU再启动发送端MCU,接收端MCU的串口能正常接收。
    2. 代码不做修改,若先启动发送端MCU再启动接收端MCU,接收端MCU的串口100%接收异常。
    3. 修改发送端代码,改为发送端MCU串口每1秒间隔发送一次,则无论启动顺序如何,接收端MCU的串口都能正常。

    3 程序分析

    由上述代码可知,程序是先在USART_Config()函数函数内初始化串口并使能,然后再在接下来的main函数的while循环内初始化DMA并使能。这个是标准库内附带的示例代码,咋一看没什么问题,但仔细一想,针对用户的使用场景,这里就会产生一个问题:由于用户的主CPU有可能在从MCU启动之前就已经有可能启动,那么在这种情况下,在初始化完串口并使能后,到DMA使能之前这段时间内,若主CPU向从MCU发送串口数据,从MCU是否能正确接收?

    从上述测试代码的结果2可以得出,若在串口初始化并使能后到DMA使能之前有数据来,MCU是不能接收的,经进一步调试,发现此时数据寄存器USART_DR存在一个数据,且在状态寄存器USART_SR中ORE值1,由此可知,串口的接收寄存器中已经接收到一个数据,但是后面的数据又来了,由于数据寄存器中的数据没有及时转移走(此时DMA还没有开启),从而导致后面的数据无法存入,所以产生了上溢错误(ORE),而一旦产生上溢错误后,就无法再触发DAM请求,及时之后再启动DMA也不行,无法触发DMA请求就无法将数据寄存器内的数据及时转移走,如此陷入死锁,这就是串口无法正常接收的原因。这时反观一下代码的结果3,这又将做如何解释?

    仔细查看测试结果3,发现这个发送端每1秒间隔发送一次,那么就会存在这个一个概率,这个发送的时间点是否刚好在接收端MCU的串口初始化并使能和DMA使能之间还是之后,这个时间窗口非常关键,如果刚好在时间窗,那么串口接收就不正常,如果在这个时间窗之后,串口接收就能正常。由于测试代码采用的是1秒间隔,对于MCU来说这个是非常大的时间长度,还是很小概率能碰中这个时间窗的,因此,测试结果看起来是都能正常,实际严格来说,还是存在刚好碰中的可能。如果间隔时间缩短,那个碰中的几率就增大。由此看来,这也就能解释测试结果3了,也能解释客户提到的有时正常有时不正常的现象了。

    4 问题处理

    处理有两种方法,第一种方法是在使能DMA后,及时将数据寄存器DR中的数据清除掉,如下代码所示:

    //...
    /* Enable the DMA Stream */
        DMA_Cmd(USARTx_RX_DMA_STREAM, ENABLE);
        /* Enable the USART Rx DMA requests */
        USART_DMACmd(USARTx, USART_DMAReq_Rx , ENABLE);
    
      while(SET ==USART_GetFlagStatus(USARTx,USART_FLAG_ORE))
      {
        Tmp =USART_ReceiveData(USARTx);
      }
      //...
    

    这里是使用读DR的方法来清除的,从参考手册中也提到使用这种方法来清除ORE标志:

    图2

    图2

    第一种方法类似于一种纠错措施,下面介绍另一种推荐的方法,如下代码所示:

    //...
    /* Enable the DMA Stream */
        DMA_Cmd(USARTx_RX_DMA_STREAM, ENABLE);
        /* Enable the USART Rx DMA requests */
        USART_DMACmd(USARTx, USART_DMAReq_Rx , ENABLE);
    
      USART_Cmd(USARTx, ENABLE);
      //...
    

    如上所示,可以先使能DMA再使能串口,这样就彻底不存在那个时间窗了,不管数据何时过来能能被DAM及时转走。这个是推荐的解决方法。

    5 结论

    标准库中的示例代码一般来说只供参考,对于大部分情况来说都是能正常工作的,但偶尔也会出现不适用的情况,此时更需要我们针对问题进行思考分析,进一步找到原因才能解决问题。对于串口使用DMA来接收的情况,这里建议一定要先使能DMA,最后使能串口,这样就能避免类似问题出现了。

    本文转自:http://www.stmcu.org/module/forum/thread-606799-1-1.html

    展开全文
  • 让DMA66 硬盘工作在DMA33 模式 (转)[@more@] 我的计算机的主板为旗舰638B型主板,采用威盛公司的VT82C693和VT82C596A 芯片组。当BIOS中对硬盘类型有关的设置都选择Auto后,会在启动...
    让DMA66 硬盘工作在DMA33 模式 (转)[@more@] 

    我的计算机的主板为旗舰638B型主板,采用威盛公司的VT82C693和VT82C596A 芯片组。当BIOS中对硬盘类型有关的设置都选择Auto后,会在启动画面中显示硬盘和光驱真正支持的最高传输模式,甚至可以显示本身并不支持的UDMA 4模式。XML:namespace prefix = o ns = "urn:schemas-microsoft-com:Office:office" />

    对于支持DMA33 传输模式的硬盘,都可以在进入windows 98后设置成DMA 模式。具体步骤为:右击“我的电脑”,选择“属性”,选择“设备管理”,分别展开“CDROM ”和“磁盘驱动器”前面的+号,分别双击代表光驱和硬盘的子项目,然后选择“设置”,选中 DMA选项。选中时会出现关于硬件不支持的警告,属正常提示,尽可以放心地重新启动。另外,若硬盘支持的是DMA66 ,则无法选中DMA 选项;即便强行选中也不会有效,反而使计算机每次启动时都出现很长时间的自动纠正等待。

    假如想要在仅支持DMA33 的主板上使用 DMA66硬盘DMA 传输特性,人们普遍认为必须配一块PCI 硬盘加速卡,或者用各硬盘厂商专门提供的DMA 转换程序,把硬盘的DMA66 转换为DMA33。然而经过本人反复试验,终于发现还有一个非常简单的方法。

    把主板中关于DMA66 硬盘的UDMA选项从默认的AUTO改成DISABLE ,屏蔽掉主板对该硬盘的UDMA支持,进入windows 98后,便可以用上面介绍的方法,利用Windows 98自带的UDMA驱动程序,让硬盘工作在DMA33 模式下。经过此方法处理后,本人的第二硬盘IBM15.2G硬盘很正常地工作在DMA33 模式下,经过Winbench99测试比较,硬盘传输率从原来的4.8M/s一下提高到11.2M/s,cpu占用率从96% 骤降至5.3%,几乎和我的第一硬盘,DMA33 火球六代6.4G的传输率12.8M/s、CPU占用率6.3%一致。

    来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/10752043/viewspace-988166/,如需转载,请注明出处,否则将追究法律责任。

    转载于:http://blog.itpub.net/10752043/viewspace-988166/

    展开全文
  • 项目简介:stm32f407实现定时器3(Timer3)触发ADC双通道同时采样并在DMA中断读取每次转换的结果 项目需求:  对两路信号进行ADC同时采样。由于一路信号将作为参考信号解调另一路信号,所以要确保两路信号的每次...

    项目简介:stm32f407实现定时器3(Timer3)触发ADC双通道同时采样并在DMA中断读取每次转换的结果

    项目需求:

      对两路信号进行ADC同时采样。由于一路信号将作为参考信号解调另一路信号,所以要确保两路信号的每次采样是同时进行的。所以,需要将ADC设置成“多重ADC模式”中的“规则同时模式”下的“双重ADC模式”(ADC_DualMode_RegSimult)。由于待采样的信号频率范围不确定,但是又要求每次采样之间的时间间隔较为精确,故需要ADC采样率可调但是又不能简单的使用delay()函数,所以要求ADC的每次转换由定时器触发ADC_ExternalTrigConvEdge_Rising)。

      其中,需要注意的点有:

    1. 多重ADC模式下想要多路ADC同步(同时)转换,只能通过DMA功能来同时获取两路ADC的转换结果到目标地址(自己定义的用于保存转换结果的数组),即便不需要DMA做大量的数据搬运工作。
    2. 要想定时器触发ADC的转换,Timer必须配置成PWM模式。
    3. 要想在DMA转换结束后及时调用转换结果,需要开启DMA传输完成的中断,然后再中断中及时对数据进行处理。

     下面,本文将一步一步记录,我是如何完成项目需求的程序功能的。


      首先,我找来了原子stm32f407探索者开发板提供的定时器例程作为模板,准备往其中添加内容完成最终的功能。

    实验8 定时器中断实验

      然而,原子的ADC教学中并没有关于ADC双通道同步采样的例程,故在某一篇博友的博文(链接遗失,感谢博友好人)中受到启发,去到st官网下载了官方的双通道adc规则同步采样的例程。下载地址链接为[下载地址][下载页面],如果下载链接失效,那么可以自己前往官网搜索stm32f407,找到名为“STM32F4 DSP and standard peripherals library”的资源下载。例程的目录如下,在本文的最后也会提供该例程的下载。

    en.stm32f4_dsp_stdperiph_lib

    --STM32F4xx_DSP_StdPeriph_Lib_V1.8.0

    ----Project

    ------STM32F4xx_StdPeriph_Examples

    --------ADC

    ----------ADC_DualModeRegulSimu

       根据例程中excel画出的图示,我们可以很清楚的看到每次两个通道同时采样完成后,结果通过DMA获取。该例程中还是使用软件触发ADC启动转换,先不管这些,我们先把这个例程和原子的定时器Timer的例程整合到一起。

    规则同步ADC采样时序示意图,来自ST官方demo
    规则同步ADC采样时序示意图,来自ST官方demo

      整合好的文件名为:

    myTest-20190203-dualADCok

      在文章的最后将会附上下载链接。

      大概来看一下这个代码做了什么事:就是在Timer3的中断里,通过调用ADC_SoftwareStartConv(ADC1);函数触发了双通道ADC的规则同步转换,然后从DMA的目标数组中读取结果,通过串口输出。关键代码如下:

      就是简单的将两个例程整合,并没有做太多别的事情。

    //定义存储转换结果的数组
    
    __IO uint16_t aADCDualConvertedValue[2];
    
    
    // ADC初始化部分
    
    ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;
    
    ……
    
    ADC_Init(ADC1, &ADC_InitStructure);
    ADC_Init(ADC2, &ADC_InitStructure);
    ADC_MultiModeDMARequestAfterLastTransferCmd(ENABLE);
    ADC_Cmd(ADC1, ENABLE);
    ADC_Cmd(ADC2, ENABLE);
    
    
    //获取ADC采样的值部分
    
    ADC_SoftwareStartConv(ADC1);
    adcVal01= aADCDualConvertedValue[0];			
    adcVal02= aADCDualConvertedValue[1];		
    sprintf(msgstr,"adc ch5=%d ch6=%d\r\n",adcVal01,adcVal02);
    printf(msgstr);
    
    
    //DMA初始化部分
    
    DMA_InitTypeDef DMA_InitStructure;
    
    DMA_InitStructure.DMA_Channel = DMA_Channel_0; 
    DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)&aADCDualConvertedValue;
    DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)ADC_CCR_ADDRESS;
    DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;
    DMA_InitStructure.DMA_BufferSize = 2;
    DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
    DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
    DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
    DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
    DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
    DMA_InitStructure.DMA_Priority = DMA_Priority_High;
    DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Enable;         
    DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull;
    DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;
    DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
    DMA_Init(DMA2_Stream0, &DMA_InitStructure);
    
    //DMA_ITConfig(DMA2_Stream0, DMA_IT_TC | DMA_IT_HT, ENABLE);
    /* DMA2_Stream0 enable */
    DMA_Cmd(DMA2_Stream0, ENABLE);
    
    

      运行结果如下:

    运行结果1

      目前,ADC的转换还是在定时器的中断中,通过调用函数,这种产生软件触发的方式进行的。


      下一步,需要将ADC的转换改为由定时器触发。那么,在改动的过程中会遇到哪些问题呢?关键代码如下:

    //ADC初始化部分
    
    ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_Rising;
    ADC_InitStructure.ADC_ExternalTrigConv= ADC_ExternalTrigConv_T3_CC1;
    
    
    //定时器初始化部分
    
    TIM_TimeBaseInit(TIM3,&TIM_TimeBaseInitStructure);
    TIM_ITConfig(TIM3,TIM_IT_Update,ENABLE); 
    
     /* TIM1 channel1 configuration in PWM mode */ 
    TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; 
    TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;                
    TIM_OCInitStructure.TIM_Pulse = 500; 
    TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low;         
    TIM_OC1Init(TIM3, &TIM_OCInitStructure); 
    TIM_CtrlPWMOutputs(TIM3, ENABLE);
    
    TIM_Cmd(TIM3,ENABLE);
    
    NVIC_InitStructure.NVIC_IRQChannel=TIM3_IRQn; 
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=0x01; 
    NVIC_InitStructure.NVIC_IRQChannelSubPriority=0x03; 
    NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;
    NVIC_Init(&NVIC_InitStructure);
    
    

      改好后的文件名为:

    myTest-20190203-dualADCandTimerTrigOk

      在文末会提供下载。主要修改的地方是:

    1. ADC初始化部分对ADC的触发方式做了修改
    2. 定时器初始化部分,将Timer配置成的PWM的模式
    3. 配置定时器相关中断

      运行结果如下:

    运行结果2

      这里,取消了定时器3溢出时的中断函数。可见,我们可以在主函数while(1)循环中,不断的读取转换结果保存数组的值,打印出来,然后发现每次读取的结果确实在随着输入信号的变化而改变。因此我们知道了,Timer触发ADC采样配置成功了。但是还并不知道在什么时候完成了一次转换。图示表明,在打印速率大于转换速率的时候,我们将每一次的采样结果打印了多遍。

    //TIM_ITConfig(TIM3,TIM_IT_Update,ENABLE); //注释掉Timer3中断

      但是,怎么才能在每次转化好了后,及时的把采样的结果获取到呢?


      其实,只需要再加上DMA传输完成后的中断函数,在DMA的中断中及时处理每次DMA传输的采样结果就行了。关键代码如下:

    //DMA初始化部分
    
    DMA_Init(DMA2_Stream0, &DMA_InitStructure);
    
    DMA_ClearITPendingBit(DMA2_Stream0, DMA_IT_TC); 
    DMA_ITConfig(DMA2_Stream0, DMA_IT_TC, ENABLE); 
    /* DMA2_Stream0 enable */
    DMA_Cmd(DMA2_Stream0, ENABLE);
    
    
    //增加DMA中断处理函数
    
    void DMA2_Stream0_IRQHandler(void) 
    {     
    	if(DMA_GetITStatus(DMA2_Stream0, DMA_IT_TCIF0)) 
    	{
    		DMA_ClearITPendingBit(DMA2_Stream0, DMA_IT_TCIF0);
    		
    		printf("DMA interrupt:\r\n");
    		adcVal01= aADCDualConvertedValue[0];			
    		adcVal02= aADCDualConvertedValue[1];		
    		sprintf(msgstr,"adc ch5=%d ch6=%d\r\n",adcVal01,adcVal02);
    		printf(msgstr);
    		printf("\r\n");
    	}
    }
    
    

      最终实现了完整功能的程序命名如下:

     myTest-20190203-dualADCandTimerTrigAndDMAinterrOk

      运行结果如下:

    运行结果3


    最后附上本文所述代码的下载链接地址:

    下载地址一:来源于CSDN的下载

    下载地址二:(点此链接之前请先给本文点个“赞”吧)来源于Github

    本文代码可直接在原子STM32F407ZGT6的战舰开发板上运行。

    感谢各位的阅读,如果您觉得有用或觉得哪里有错误,希望您能够留言表示支持。

    展开全文
  • stm32 usart在DMA模式下只能发送一次

    万次阅读 热门讨论 2016-09-12 10:47:43
    问题描述:使用STM32 cube生成usart2 DMA direct mode(不使用FIFO,normal模式,STM32... 单步调试发现DMA方式下的发送发送第一次之后,husart->State 标志变为 HAL_USART_STATE_BUSY就再也不变了。比较直接的解决思

      问题描述:使用STM32 cube生成usart2 DMA direct mode(不使用FIFO,normal模式,STM32f407)配置代码,usart2可以使用阻塞方式发送,使用DMA发送则只能发送第一次,复位后还只能发送一次。

      单步调试发现DMA方式下的发送在发送第一次之后,husart->State 标志变为 HAL_USART_STATE_BUSY就再也不变了。比较直接的解决思路就是在DMA发送中断中给这个标志修改为HAL_USART_STATE_READY,修改之后还是不好用(我认为是可以通过修改多个相关寄存器解决的,但是个人倾向于不深入了解其寄存器,而是用封装度更高的HAL系列函数)。

      读stm32f4xx_hal_usart.c(V1.5.0)文件的前面关于如何使用HAL函数的部分并与配置代码比较并没有发现问题,但是看stm32f1xx_hal_usart.c(V1.0.0)在同样的位置多了如下文字:

                  (+++) Configure the USARTx interrupt priority and enable the NVIC USART IRQ handle
         (used for last byte sending completion detection in DMA non circular mode)

      翻看STM32F4系列早于1.5.0的文件都没有这句,可能是官方的疏忽或者是个人理解不到位,总之增加了USART2中断之后(cube生成的),usart DMA发送是完全正常了。

    展开全文
  • 应用背景: 一个双通道DO输出芯片...把反馈引脚接到单片机的ADC,然后程序中进行切换。代码如下: void Adc2_init(void) { ADC_InitTypeDef ADC_InitStructure; ADC_CommonInitTypeDef ADC_CommonInitStruct...
  • 我的计算机的主板为旗舰638B型主板,采用威盛公司的VT82C693和VT82C596A 芯片组...对于支持DMA33 传输模式的硬盘,都可以进入Windows 98后设置成DMA 模式。具体步骤为:右击“我的电脑”,选择“属性”,选择“设备管
  • 文章来源:http://blog.csdn.net/xiaozuo/archive/2001/01/19/5151.aspx 转载于:https://www.cnblogs.com/zhaoxiaoyang2/archive/2001/01/19/816635.html
  • DMA

    2019-09-23 10:43:26
    什么是DMA DMA,Direct Memory Access,直接内存访问,是一种不经过CPU而直接从内存存取数据的数据交换...在DMA模式下,CPU只需要向DMA控制器下达指令,传输数据由DMA来完成,数据传送完再把信息反馈给CPU,这...
  • dma

    2013-05-09 23:12:01
    DMA的英文拼写是“Direct ...而在DMA模式下,CPU只须向DMA控制器下达指令,让DMA控制器来处理数据的传送,数据传送完毕再把信息反馈给CPU,这样就很大程度上减轻了CPU资源占有率。DMA模式与PIO模式的区别就在于,DM
  • SG DMA与普通DMA(block DMA)的区别

    千次阅读 2018-01-10 14:10:34
    在DMA传输数据的过程中,要求源物理地址和目标物理地址必须是连续的。但是在某些计算机体系中,如IA架构,连续的存储器地址在物理上不一定是连续的,所以DMA传输要分成多次完成。如果在传输完一块物理上连续的数据后...
  • DMA传送

    2020-09-15 15:01:58
    目录DMA的由来两种由CPU控制的传送方式程序传送方式无条件传送方式查询(有条件)传送方式中断传送方式CPU控制传送方式总结DMA原理DMA的传送过程预处理数据传送后处理...在DMA出现之前,CPU与外设之间的数据传送方式
  • DMA之理解

    万次阅读 多人点赞 2018-09-12 12:32:37
    在DMA出现之前,CPU与外设之间的数据传送方式有程序传送方式、中断传送方式。CPU是通过系统总线与其他部件连接并进行数据传输。 1.1程序传送方式 程序传送方式是指直接在程序控制下进行数据的输入/输出操作。...
  • DMA摘记

    2017-10-11 10:43:00
    在DMA模式下,CPU只须向DMA控制器下达指令,让DMA控制器来处理数据的传送,数据传送完毕再把信息反馈给CPU,这样就很大程度上减轻了CPU资源占有率。DMA模式与PIO模式的区别就在于,DMA模式不过分依赖CPU,可以大大...
  • 关于DMA

    2018-05-17 17:49:00
    用串口在dma中发东西的时候,,, 要判断DMA里是不是由东西,是不是在占用 当多个外设再用DMA的时候,,,要查看DMA有没有占用 一包数没发完,不要再传另一包 转载于:...
  • DMA知识

    2017-11-20 15:37:21
    DMA(Direct Memory Access,...在DMA模式下,CPU只须向DMA控制器下达指令,让DMA控制器来处理数据的传送,数据传送完毕再把信息反馈给CPU,这样就很大程度上减轻了CPU资源占有率,可以大大节省系统资源。DMA方式是一

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 6,032
精华内容 2,412
关键字:

在dma