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

发布者:CuriousTraveler最新更新时间: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  双缓冲机制  初始化 引用地址:STM32双缓冲机制初始化(使用STM32CubeMX)

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

推荐阅读最新更新时间:2024-11-09 02:57

基于STM32的实收实发超声波检测系统研究
1、引言 在高频的超声波数据采集及频率分析的应用中,通常会采用实收实发的系统来模拟收到信号,目前最经常采用的模式是使用下位机高速连续采样,上位机进行数据分析的模式,然后在将检测的信号通过D/A发送出去。这种模式可以完成M级甚至于G级的数据连续采样,目前已经在高速的工业信号采集中得到了广泛的应用。 提出基于STM32的实收实发系统,主控芯片采用目前最新的STM32F407芯片,属于ARM公司推出的最新一代低功耗高性能片上系统,内核为CORTexM4,最高主频可以到168MHz,内部采用ARM的精简指令集,单周期指令,并且集成了ARM公司的浮点DSP指令集,可以对数据进行信号滤波以及FFT运算,计算能力超过TI的200M主频的DS
[单片机]
基于<font color='red'>STM32</font>的实收实发超声波检测系统研究
STM32按键中断应用实例
STM32按键中断(HAL库版) 本文将介绍如何使用STM32F4的IO口作为中断触发源,通过串口显示按键被按下的日志。 1.运用到的资源、工具: 1.1开发板芯片STM32F407,PI9作为外部中断源、USART3串口向屏幕传输信息 1.2编译工具:MDK-ARM V5(keil5) 1.3辅助工具:STM32CubeMX 2.硬件设计 2.1原理图: 3.软件设计 3.1STM32cubeMX配置工程文件 选择Key1作为外部中断源、选择中断触发方式为下降沿触发、并设置中断优先级分组选择优先级 使能USART3串口配置为异步通信 最后生成工程文件 3.2串口输出重定向(重
[单片机]
<font color='red'>STM32</font>按键中断应用实例
STM32 芯片架构
把STM32 想像类比成一台电脑。 CPU 通过 总线(Bus) 控制各类外设。 各部分功能如下: CPU:包含运算器,控制器及若干寄存器,是单片机的控制和指挥中心。 ROM (STM32中称为FLASH):用于存放程序和数据,为只读储存器。更改(擦除)和写入程序都较为麻烦, 需要遵守FLASH相关的协议。可以认为是计算机的硬盘。 RAM(STM32中称为SRAM):用于存放运算的中间结果、数据暂存及数据缓冲等。可以随机读入或读出,读写速度快,读写方便;但是断电或复位会丢失数据。可以认为是计算机的内存。 总线矩阵:总线矩阵用于主控总线之间的访问仲裁管理,提高了各部件交流的效率。 寄存器:虽然图里面没有寄存器,但
[单片机]
<font color='red'>STM32</font> 芯片架构
STM32 assert_param
在STM32的固件库和提供的例程中,到处都可以见到assert_param()的使用。如果打开任何一个例程中的stm32f10x_conf.h文件,就可以看到实际上assert_param是一个宏定义;在固件库中,它的作用就是检测传递给函数的参数是否是有效的参数。 所谓有效的参数是指满足规定范围的参数,比如某个参数的取值范围只能是小于3的正整数,如果给出的参数大于3,则这个assert_param()可以在运行的程序调用到这个函数时报告错误,使程序员可以及时发现错误,而不必等到程序运行结果的错误而大费周折。 这是一种常见的软件技术,可以在调试阶段帮助程序员快速地排除那些明显的错误。 它确实在程序的运行上牺牲了效率(但只
[单片机]
STM32 I2C硬件的结构
引子 STM32的硬件I2C很多人都对它望而却步。因为很多电工都说,STM32 硬件 I2C有BUG、不稳定、死机等等……最后都使用GPIO模拟I2C。 的确,模拟I2C好用。但是在我看来在一个72M的Cortex-M3的MCU上这样做非常不妥。一般来说I2C是一种慢速总线,就算工作在400kHz的快速模式上,I2C传送每个字节仍需要至少23us——还没有计算地址、起始信号和结束信号的发送。如果使用GPIO模拟的I2C,这23us的CPU时间都在空转中浪费了,而这23us已经可以做不少的事情了,所以在STM32上I2C还是使用硬件为佳——虽然它多多少少有点缺陷。 这篇文章不是给完全没有接触过STM32 硬件I2C的新手看的
[单片机]
<font color='red'>STM32</font> I2C硬件的结构
STM32为例,介绍单片机中的BOR/POR/PDR
STM32内部自带了一个可编程电压检测器(PVD),对VDD的电压进行监控可以通过电源控制寄存器PLS 位来设置监控电压的阀值,这样通过与VDD电压比较达到了监控电压的目的。 电源控制状态寄存器(PWR_CSR)中的PVDO用来表明VDD是高于还是低于PVD的电压阀值。当VDD下降到PVD阀值以下或VDD上升到PVD阀值之上时,通过外部中断16线上升或下降边沿触发设置,产生PVD中断。在中断处理函数中做相应的保护措施。 具体由以下图片和表格所示。 图1:阀值与PVD输出关系 表:具体寄存器参数 下面对上面的图片和表格中的数据做一个简要的解释: (1) PVD = Programmable Votage Detec
[单片机]
STM32】HAL库-基本定时器
简介 基本定时器TIM6和TIM7各包含一个16位自动装载计数器,由各自的可编程预分频器驱动。它们可以作为通用定时器提供时间基准,特别地可以为数模转换器(DAC)提供时钟。实际上,它们在芯片内部直接连接到DAC并通过触发输出直接驱动DAC。这2个定时器是互相独立的,不共享任何资源。 寄存器 软件可以读写计数器CNT、自动重装载寄存器ARR和预分频寄存器PSC,即使计数器运行时也可以操作。 当前计数值寄存器CNT 向上计数,可随时修改 自动重装载寄存器ARR 可随时修改,具有影子寄存器,根据TIMx_CR1寄存器中的自动重装载预加载使能位(ARPE),写入ARR寄存器的内容能够立即或在每次更新事件(UEV)时,传送到它
[单片机]
【<font color='red'>STM32</font>】HAL库-基本定时器
stm32学习笔记(一) GPIO
战舰开发板的程序 main函数 int main(void) { delay_init(); //延时函数初始化 LED_Init(); //初始化与led连接的硬件配置 while(1) { LED0=1; LED1=1; delay_ms(300); LED0=0; LED1=0; delay_ms(300); } } delay_init();函数 void delay_init() { #ifdef OS_CRITICAL_METHOD //如果OS_CRITICAL_METHOD定义了,说明使用ucosII了. u32 reload; #e
[单片机]
小广播
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

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

换一换 更多 相关热搜器件
随便看看

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

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