datasheet

STM32双缓冲机制初始化(使用STM32CubeMX)

2019-05-24来源: eefocus关键字:STM32  双缓冲机制  初始化

1.使用STM32CubeMX配置的串口引脚设置和dma的设置会生成在usart.c。


  1)如果DMA接收想采用循环缓冲区的方式,可以直接将RX-DMA设置成Circle方式,然后数据就会硬件上自动实现环形缓冲区的功能,省了不少时间。


  2)DMA在采用Normal模式的时候,当一次任务完成后,DMA->DMA_BufferSize自动清零,并且DMA自动停止。如果想再次设置DMA的BufferSize的话,必须要进行如下操作:


   step1:DMA_CMD(DMAx_Channely,DISABLE);


   step2: 设置DMA_BufferLen


   step3:DMA_CMD(DMAx_Channely,ENABLE)


  3)DMA采用Circle模式的时候,在发送或者接受完成之后,仍然保存着BufferSize,并且DMA还处于使能状态,一直连续工作,直到用户停止DMA


else if(uartHandle->Instance==USART1)

  {

  /* USER CODE BEGIN USART1_MspInit 0 */

 

  /* USER CODE END USART1_MspInit 0 */

    /* USART1 clock enable */

    __HAL_RCC_USART1_CLK_ENABLE();

  

    /**USART1 GPIO Configuration    

    PA9     ------> USART1_TX

    PA10     ------> USART1_RX 

    */

    GPIO_InitStruct.Pin = GPIO_PIN_9|GPIO_PIN_10;

    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;

    GPIO_InitStruct.Pull = GPIO_PULLUP;

    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;

    GPIO_InitStruct.Alternate = GPIO_AF7_USART1;

    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

 

    /* USART1 DMA Init */

    /* USART1_RX Init */

    hdma_usart1_rx.Instance = DMA2_Stream2;

    hdma_usart1_rx.Init.Channel = DMA_CHANNEL_4;

    hdma_usart1_rx.Init.Direction = DMA_PERIPH_TO_MEMORY;

    hdma_usart1_rx.Init.PeriphInc = DMA_PINC_DISABLE;

    hdma_usart1_rx.Init.MemInc = DMA_MINC_ENABLE;

    hdma_usart1_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;

    hdma_usart1_rx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;

    hdma_usart1_rx.Init.Mode = DMA_NORMAL; //这里设成DMA_CIRCULAR和DMA_NORMAL好像没有对双缓冲造成影响

    hdma_usart1_rx.Init.Priority = DMA_PRIORITY_LOW;

    hdma_usart1_rx.Init.FIFOMode = DMA_FIFOMODE_DISABLE;

    if (HAL_DMA_Init(&hdma_usart1_rx) != HAL_OK)

    {

      _Error_Handler(__FILE__, __LINE__);

    }

 

    __HAL_LINKDMA(uartHandle,hdmarx,hdma_usart1_rx);

 

    /* USART1_TX Init */

    hdma_usart1_tx.Instance = DMA2_Stream7;

    hdma_usart1_tx.Init.Channel = DMA_CHANNEL_4;

    hdma_usart1_tx.Init.Direction = DMA_MEMORY_TO_PERIPH;

    hdma_usart1_tx.Init.PeriphInc = DMA_PINC_DISABLE;

    hdma_usart1_tx.Init.MemInc = DMA_MINC_ENABLE;

    hdma_usart1_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;

    hdma_usart1_tx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;

    hdma_usart1_tx.Init.Mode = DMA_NORMAL;

    hdma_usart1_tx.Init.Priority = DMA_PRIORITY_LOW;

    hdma_usart1_tx.Init.FIFOMode = DMA_FIFOMODE_DISABLE;

    if (HAL_DMA_Init(&hdma_usart1_tx) != HAL_OK)

    {

      _Error_Handler(__FILE__, __LINE__);

    }

 

    __HAL_LINKDMA(uartHandle,hdmatx,hdma_usart1_tx);

 

    /* USART1 interrupt Init */

    HAL_NVIC_SetPriority(USART1_IRQn, 5, 0);

    HAL_NVIC_EnableIRQ(USART1_IRQn);

  /* USER CODE BEGIN USART1_MspInit 1 */

 

  /* USER CODE END USART1_MspInit 1 */

  }

 


2.下面是关于DMA双缓冲机制的配置,特别说明一下,我先__HAL_DMA_DISABLE(hdma); 再配置后面的参数。DMA才正常接收数据了。


static HAL_StatusTypeDef DMAEx_MultiBufferStart_IT(DMA_HandleTypeDef *hdma,

                                                   uint32_t SrcAddress,

                                                   uint32_t DstAddress,

                                                   uint32_t SecondMemAddress,

                                                   uint32_t DataLength)

{

  HAL_StatusTypeDef status = HAL_OK;

  

  /* Memory-to-memory transfer not supported in double buffering mode */

  if (hdma->Init.Direction == DMA_MEMORY_TO_MEMORY)

  {

    hdma->ErrorCode = HAL_DMA_ERROR_NOT_SUPPORTED;

    return HAL_ERROR;

  }

  

  /* Set the UART DMA transfer complete callback */

  /* Current memory buffer used is Memory 1 callback */

  hdma->XferCpltCallback   = dma_m0_rxcplt_callback; //第一个缓冲区填满后会调用这个函数

  /* Current memory buffer used is Memory 0 callback */

  hdma->XferM1CpltCallback = dma_m1_rxcplt_callback; ////第二个缓冲区填满后会调用这个函数

  

  /* Check callback functions */

  if ((NULL == hdma->XferCpltCallback) || (NULL == hdma->XferM1CpltCallback))

  {

    hdma->ErrorCode = HAL_DMA_ERROR_PARAM;

    return HAL_ERROR;

  }

  

  /* Process locked */

  __HAL_LOCK(hdma);

    /* Enable the peripheral */

    __HAL_DMA_DISABLE(hdma);   //先要禁止DMA后面的设置才会生效

  

  //if(HAL_DMA_STATE_READY == hdma->State)

  //{

    /* Change DMA peripheral state */

    hdma->State = HAL_DMA_STATE_BUSY;

    /* Initialize the error code */

    hdma->ErrorCode = HAL_DMA_ERROR_NONE;

    /* Enable the Double buffer mode */

    hdma->Instance->CR |= (uint32_t)DMA_SxCR_DBM;

    /* Configure DMA Stream destination address */

    hdma->Instance->M1AR = SecondMemAddress;

    

    /* Configure DMA Stream data length */

    hdma->Instance->NDTR = DataLength;

    /* Configure the source, destination address */

    if((hdma->Init.Direction) == DMA_MEMORY_TO_PERIPH)

    {

      hdma->Instance->PAR = DstAddress;

      hdma->Instance->M0AR = SrcAddress;

    }

    else

    {

      hdma->Instance->PAR = SrcAddress;

      hdma->Instance->M0AR = DstAddress;

    }

    

    /* Clear TC flags */

    __HAL_DMA_CLEAR_FLAG (hdma, __HAL_DMA_GET_TC_FLAG_INDEX(hdma));

    /* Enable TC interrupts*/

    hdma->Instance->CR  |= DMA_IT_TC;

    

    /* Enable the peripheral */

    __HAL_DMA_ENABLE(hdma);

    

    /* Change the DMA state */

    hdma->State = HAL_DMA_STATE_READY;

  //}

  //else

  //{

  //  /* Return error status */

  //  status = HAL_BUSY;

  //}

  

  /* Process unlocked */

  __HAL_UNLOCK(hdma);

  

  return status; 

}

 

void debug_uart_init(void)

{

  //open uart idle it

  __HAL_UART_CLEAR_IDLEFLAG(&DEBUG_HUART);

  __HAL_UART_ENABLE_IT(&DEBUG_HUART, UART_IT_IDLE);//设置了空闲中断。进入空闲中断就可以考虑处理数据了。如果数据量大就放到专门的任务里处理。

  

  // Enable the DMA transfer for the receiver request

  SET_BIT(DEBUG_HUART.Instance->CR3, USART_CR3_DMAR);

  

  DMAEx_MultiBufferStart_IT(DEBUG_HUART.hdmarx,

                           (uint32_t)&DEBUG_HUART.Instance->DR,

                           (uint32_t)debug_dma_rxbuff[0],

                           (uint32_t)debug_dma_rxbuff[1],

                           UART_RX_DMA_SIZE);

  

}

 


关键字:STM32  双缓冲机制  初始化

编辑:什么鱼 引用地址:http://www.eeworld.com.cn/mcu/ic462832.html
本网站转载的所有的文章、图片、音频视频文件等资料的版权归版权所有人所有,本站采用的非本站原创文章及图片等内容无法一一联系确认版权者。如果本网所选内容的文章作者及编辑认为其作品不宜公开自由传播,或不应无偿使用,请及时通过电子邮件或电话通知我们,以迅速采取适当措施,避免给双方造成不必要的经济损失。

上一篇:STM32F407各定时器的时钟频率
下一篇:STM32之TIM 舵机控制PWM

关注eeworld公众号 快捷获取更多信息
关注eeworld公众号
快捷获取更多信息
关注eeworld服务号 享受更多官方福利
关注eeworld服务号
享受更多官方福利

推荐阅读

学习STM32CubeMX与HAL库吐槽

最近因为一个小项目(智能穿戴),用到了STM32L0(低功耗 Cortex M0)系列的MCU,查了官网,居然没有提供固件库,只有HAL库,于是STM32CubeMX生成了HAL库的工程,学习HAL的使用:STM32CubeMX与HAL库的优点:1、降低了使用外设的门槛,所有时钟设置等一目了然。2、统一了代码的架构、风格,让源代码的可读性“保底线“提高。吐槽如下:1、工程的架构很死了,只能在框框条条里填写内容,这完全违背了C程序员们的习惯。例如,要自己加上OS,代码结构会很难看。2、但一但遇上了坑,就无法解决。3、依赖性更高了,而且这工具有BUG,例如:在生成代码时,终止STM32CubeMX,所有源代码会全部消失,自己写的代码
发表于 2019-06-18

STM32CubeMx(Keil5)开发之路——1配置第一个项目

运行环境Windows10STM32CubeMX___Version 5.0.0Keil5(MDK5)___Version 5.15简介本例程主要搭建第一个项目,并且完成最基本的项目所需配置,后续的教程都基于这篇教程。STM32CubeMx配置新建项目搜索自己芯片的型号点击选择封装形式选择外部晶振可以根据需求调节各个总线的时钟频率(就具体情况而定)DEBUG选项选择"Serial Wire"(4线烧录,CLK,DIO,VCC,GND)你会看到芯片引脚会占用这几个引脚,就是烧录用的CLK和DIO点击"Project Manager"修改项目名称修改项目保存路径选择编写工具(我使用Keil5
发表于 2019-06-18
STM32CubeMx(Keil5)开发之路——1配置第一个项目

STM32CubeMX(Keil5)开发之路——9设置微秒级别的延时

运行环境Windows10STM32CubeMX___Version 5.0.0Keil5(MDK5)___Version 5.15简介本例程主要讲解如何对芯片内的Flash进行读写,用芯片内部Flash可以对一些需要断电保存的数据进行保存,无需加外部得存储芯片,本例程采用的是STM32F103ZET6,512K大小的Flash。STM32CubeMx基本配置基础配置过程请参考 STM32CubeMx(Keil5)开发之路—配置第一个项目printf重定向例程请参考 STM32CubeMx(Keil5)开发之路——3发送USART数据和printf重定向STM32CubeMx PWM配置1——点击TIM3进行设置2——选择
发表于 2019-06-18
STM32CubeMX(Keil5)开发之路——9设置微秒级别的延时

STM32CubeMX(Keil5)开发之路——7输出PWM

运行环境Windows10STM32CubeMX___Version 5.0.0Keil5(MDK5)___Version 5.15简介本例程主要讲解如何设置PWM这只输出4路PWM信号STM32CubeMx基本配置基础配置过程请参考 STM32CubeMx(Keil5)开发之路—配置第一个项目STM32CubeMx PWM配置1——点击TIM2进行设置2——4个Channel都选择 “PWM Generation CHx” 选项3——预分频值填72-1即714——自动重装载值设置为100-1也就是995——会看到相应的输出管脚PA0——PA3就是PWM的输出管脚讲解:PWM波的频率=时钟频率/(预分频+1)/(自动重装载值
发表于 2019-06-18
STM32CubeMX(Keil5)开发之路——7输出PWM

关于STM32像EPROM一样可以单字节写内部Flash的理解

都有说STM32的内部Flash可以像EPROM一样操作,单个字节单个字节的写入。根据本人的拙见,其实也就仅仅是“像”而已。原因有以下几点:1.首先Flash这种东西,其写入数据的原理是便是将1变成0,所以你的某地址Flash一旦已经写过数据而且不为0,则当你再次需要向该地址写数据时,必须要先擦除,即把该地址先全部变成1,否则你将数据写入该地址后,基本上该地址里面的值已经不是你写入的值了。2.STM32对内部Flash有页(1k或者2K)擦除指令,也就是STM32不能单独对某一个或者某几个字节进行擦除。而擦除操作并不需要大量内存。3.如果要像EPROM一样操作Flash,其原理是先把该一页里面的数据全部读到一个buf里面,如果
发表于 2019-06-18

STM32的ISP升级详解

最近在做一个给STM32用ISP升级的项目,接触到STM32厂家烧录的Bootloader工作流程,具体官方文档稍后上传供大家参考,也可去ST官网下载文档。接下来针对文档中部分内容分析其工作过程:一、要进入该模式,需把STM32硬件上的BOOT0引脚拉高(置1),BOOT1拉低(置0),对此部分不明白的可以查阅STM32BOOT引脚的资料(网上一搜一大堆),不过多阐述。两个引脚配置好对STM32复位,其在4个时钟周期内会自动检测BOOT引脚相应的配置情况,进入相应模式(原厂Bootloader模式)下工作,此时已经到达此次旅行的起点——USART Bootloader 模式此处要特别注意的是硬件上一定要用原厂规定的串口才能完成
发表于 2019-06-18
STM32的ISP升级详解

小广播

何立民专栏

单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

电子工程世界版权所有 京ICP证060456号 京ICP备10001474号 电信业务审批[2006]字第258号函 京公海网安备110108001534 Copyright © 2005-2019 EEWORLD.com.cn, Inc. All rights reserved