STM32H7的DMA双缓冲控制IO输出脉冲

keil的sct文件配置

; *************************************************************
; *** Scatter-Loading Description File generated by uVision ***
; *************************************************************

LR_IROM1 0x08000000 0x00200000  {    ; load region size_region
  ER_IROM1 0x08000000 0x00200000  {  ; load address = execution address
   *.o (RESET, +First)
   *(InRoot$$Sections)
   .ANY (+RO)
  }
  
  RW_IRAM1 0x20000000 0x00020000  {  ; RW data - 128KB DTCM
   .ANY (+RW +ZI)
  }
  
  RW_IRAM2 0x24000000 0x00080000  {  ; RW data - 512KB AXI SRAM
   *(.RAM_D1) 
  }
  
  RW_IRAM3 0x30000000 0x00048000  {  ; RW data - 128KB SRAM1(0x30000000) + 128KB SRAM2(0x3002 0000) + 32KB SRAM3(0x30040000)
   *(.RAM_D2)
  }
  
  RW_IRAM4 0x38000000 0x00010000  {  ; RW data - 64KB SRAM4(0x38000000)
   *(.RAM_D3)
  }
}

MPU配置

/* 配置 SRAM4 的属性为 Write through, read allocate,no write allocate */
MPU_InitStruct.Enable = MPU_REGION_ENABLE;
MPU_InitStruct.BaseAddress = 0x38000000;
MPU_InitStruct.Size = ARM_MPU_REGION_SIZE_64KB;
MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS;
MPU_InitStruct.IsBufferable = MPU_ACCESS_NOT_BUFFERABLE;
MPU_InitStruct.IsCacheable = MPU_ACCESS_CACHEABLE;
MPU_InitStruct.IsShareable = MPU_ACCESS_NOT_SHAREABLE;
MPU_InitStruct.Number = MPU_REGION_NUMBER2;
MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL0;
MPU_InitStruct.SubRegionDisable = 0x00;
MPU_InitStruct.DisableExec = MPU_INSTRUCTION_ACCESS_ENABLE;
HAL_MPU_ConfigRegion(&MPU_InitStruct);

初始化DMA双缓冲

在这里插入图片描述

/*初始化变量*/
#elif defined ( __CC_ARM )
ALIGN_32BYTES(__attribute__((section (".RAM_D3"))) uint32_t IO_Toggle[8]) =
 { 
 0x00000002U, 
 0x00020000U, 
 0x00000002U, 
 0x00020000U, 
 0x00000002U, 
 0x00020000U, 
 0x00000002U, 
 0x00020000U, 
 };
ALIGN_32BYTES(__attribute__((section (".RAM_D3"))) uint32_t IO_Toggle1[8]) =
 { 
 0x00000002U, 
 0x00020000U, 
 0x00000002U, 
 0x00020000U, 
 0x00000002U, 
 0x00020000U, 
 0x00000002U, 
 0x00020000U, 
 };
#endif
void bsp_InitTimDMA(void)
{
    GPIO_InitTypeDef  GPIO_InitStruct;
    DMA_HandleTypeDef DMA_Handle = {0};
    HAL_DMA_MuxRequestGeneratorConfigTypeDef dmamux_ReqGenParams = {0};

    /*##-1- 配置PB1用于PWM输出 ##################################################*/
    __HAL_RCC_GPIOB_CLK_ENABLE();
    GPIO_InitStruct.Pin = GPIO_PIN_1;
    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
    HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
  
    /*##-2- 使能DMA1时钟并配置 ##################################################*/
    __HAL_RCC_DMA1_CLK_ENABLE();
    DMA_Handle.Instance                 = DMA1_Stream1;            /* 使用的DMA1 Stream1 */
    DMA_Handle.Init.Request             = DMA_REQUEST_GENERATOR0;  /* 请求类型采用的DMAMUX请求发生器通道0 */  
    DMA_Handle.Init.Direction           = DMA_MEMORY_TO_PERIPH;    /* 传输方向是从存储器到外设 */  
    DMA_Handle.Init.PeriphInc           = DMA_PINC_DISABLE;        /* 外设地址自增禁止 */ 
    DMA_Handle.Init.MemInc              = DMA_MINC_ENABLE;         /* 存储器地址自增使能 */  
    DMA_Handle.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD;     /* 外设数据传输位宽选择字,即32bit */     
    DMA_Handle.Init.MemDataAlignment    = DMA_MDATAALIGN_WORD;     /* 存储器数据传输位宽选择字,即32bit */    
    DMA_Handle.Init.Mode                = DMA_CIRCULAR;            /* 循环模式 */   
    DMA_Handle.Init.Priority            = DMA_PRIORITY_LOW;        /* 优先级低 */  
    DMA_Handle.Init.FIFOMode            = DMA_FIFOMODE_DISABLE;    /* 禁止FIFO*/
    DMA_Handle.Init.FIFOThreshold       = DMA_FIFO_THRESHOLD_FULL; /* 禁止FIFO此位不起作用,用于设置阀值 */
    DMA_Handle.Init.MemBurst            = DMA_MBURST_SINGLE;       /* 禁止FIFO此位不起作用,用于存储器突发 */
    DMA_Handle.Init.PeriphBurst         = DMA_PBURST_SINGLE;       /* 禁止FIFO此位不起作用,用于外设突发 */
 
    /* 初始化DMA */
    if(HAL_DMA_Init(&DMA_Handle) != HAL_OK)
    {
		Error_Handler(__FILE__, __LINE__);     
    }

    /* 开启DMA1 Stream1的中断 */
    HAL_NVIC_SetPriority(DMA1_Stream1_IRQn, 2, 0);
    HAL_NVIC_EnableIRQ(DMA1_Stream1_IRQn); 

    
    /*##-4- 配置DMAMUX ###########################################################*/
    dmamux_ReqGenParams.SignalID  = HAL_DMAMUX1_REQ_GEN_TIM12_TRGO;         /* 请求触发器选择LPTIM2_OUT */
    dmamux_ReqGenParams.Polarity  = HAL_DMAMUX_REQ_GEN_RISING;              /* 上升沿触发  */
    dmamux_ReqGenParams.RequestNumber = 1;                                  /* 触发后,传输进行1次DMA传输 */

    HAL_DMAEx_ConfigMuxRequestGenerator(&DMA_Handle, &dmamux_ReqGenParams); /* 配置DMAMUX */
    HAL_DMAEx_EnableMuxRequestGenerator (&DMA_Handle);                      /* 使能DMAMUX请求发生器 */   
 
    
    /*##-4- 启动DMA双缓冲传输 ################################################*/
    /*
        1、此函数会开启DMA的TC,TE和DME中断
        2、如果用户配置了回调函数DMA_Handle.XferHalfCpltCallback,那么函数HAL_DMA_Init会开启半传输完成中断。
        3、如果用户使用了DMAMUX的同步模式,此函数会开启同步溢出中断。
        4、如果用户使用了DMAMUX的请求发生器,此函数会开始请求发生器溢出中断。
    */
    HAL_DMAEx_MultiBufferStart_IT(&DMA_Handle, (uint32_t)IO_Toggle, (uint32_t)&GPIOB->BSRRL,(uint32_t)IO_Toggle1, 8);
    
    /* 用不到的中断可以直接关闭 */
    //DMA1_Stream1->CR &= ~DMA_IT_DME; 
    //DMA1_Stream1->CR &= ~DMA_IT_TE;
    //DMAMUX1_RequestGenerator0->RGCR &= ~DMAMUX_RGxCR_OIE;
    
    TIM12_Config(0);
}

初始化TIM12用处触发DMAMUX的请求发生器

/*
*********************************************************************************************************
*	函 数 名: TIM12_Config
*	功能说明: 配置TIM12,用于触发DMAMUX的请求发生器
*	形    参: _Mode 
*             0 表示配置为100KHz触发频率,配置为100KHz触发频率,如果DMAMUX配置为单边沿触发,那么输出PWM频
*               率是50KHz,双边沿是100KHz。
*			  1 表示配置为10KHz触发频率,如果DMAMUX配置为单边沿触发,那么输出PWM频率是5KHz,双边沿是10KHz。									  
*	返 回 值: 无
*********************************************************************************************************
*/
void TIM12_Config(uint8_t _Mode)
{
    TIM_HandleTypeDef  htim ={0};
    TIM_MasterConfigTypeDef sMasterConfig = {0};
    TIM_OC_InitTypeDef sConfig = {0};
    uint32_t Period[2] = {1999, 19999};
    uint32_t Pulse[2]  = {999, 9999};

  	/* 使能时钟 */  
  	__HAL_RCC_TIM12_CLK_ENABLE();
      
    /*-----------------------------------------------------------------------
		bsp.c 文件中 void SystemClock_Config(void) 函数对时钟的配置如下: 

        System Clock source       = PLL (HSE)
        SYSCLK(Hz)                = 400000000 (CPU Clock)
        HCLK(Hz)                  = 200000000 (AXI and AHBs Clock)
        AHB Prescaler             = 2
        D1 APB3 Prescaler         = 2 (APB3 Clock  100MHz)
        D2 APB1 Prescaler         = 2 (APB1 Clock  100MHz)
        D2 APB2 Prescaler         = 2 (APB2 Clock  100MHz)
        D3 APB4 Prescaler         = 2 (APB4 Clock  100MHz)

        因为APB1 prescaler != 1, 所以 APB1上的TIMxCLK = APB1 x 2 = 200MHz;
        因为APB2 prescaler != 1, 所以 APB2上的TIMxCLK = APB2 x 2 = 200MHz;
        APB4上面的TIMxCLK没有分频,所以就是100MHz;

        APB1 定时器有 TIM2, TIM3 ,TIM4, TIM5, TIM6, TIM7, TIM12, TIM13, TIM14,LPTIM1
        APB2 定时器有 TIM1, TIM8 , TIM15, TIM16,TIM17

        APB4 定时器有 LPTIM2,LPTIM3,LPTIM4,LPTIM5

    TIM12CLK = 200MHz/(Period + 1) / (Prescaler + 1)
    函数bsp_InitTimDMA1中DMAMUX1选择的是单边沿触发,每个时钟可以触发两次。
	----------------------------------------------------------------------- */  
    HAL_TIM_Base_DeInit(&htim);
    
    htim.Instance = TIM12;
	htim.Init.Period            = Period[_Mode];
	htim.Init.Prescaler         = 0;
	htim.Init.ClockDivision     = 0;
	htim.Init.CounterMode       = TIM_COUNTERMODE_UP;
	htim.Init.RepetitionCounter = 0;
	HAL_TIM_Base_Init(&htim);
    
    sConfig.OCMode     = TIM_OCMODE_PWM1;
    sConfig.OCPolarity = TIM_OCPOLARITY_LOW;

    /* 占空比50% */
    sConfig.Pulse = Pulse[_Mode];  
    if(HAL_TIM_OC_ConfigChannel(&htim, &sConfig, TIM_CHANNEL_1) != HAL_OK)
    {
		Error_Handler(__FILE__, __LINE__);
    }

    /* 启动OC1 */
    if(HAL_TIM_OC_Start(&htim, TIM_CHANNEL_1) != HAL_OK)
    {
		Error_Handler(__FILE__, __LINE__);
    }
    
    /* TIM12的TRGO用于触发DMAMUX的请求发生器 */
	sMasterConfig.MasterOutputTrigger = TIM_TRGO_OC1REF;
    sMasterConfig.MasterOutputTrigger2 = TIM_TRGO2_RESET;
	sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;

	HAL_TIMEx_MasterConfigSynchronization(&htim, &sMasterConfig);
}
  • 11
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
STM32 ADC DMA双缓冲是一种使用STM32控制器的ADC(模数转换器)和DMA(直接存储器访问)功能的技术。 当使用ADC进行模数转换时,数据通常以连续的方式从ADC缓冲区读取。但是,在某些应用中,这可能会导致数据丢失或错位。为了解决这个问题,STM32控制器提供了双缓冲模式。 在双缓冲模式下,STM32DMA控制器可以同时访问两个ADC转换数据缓冲区。在开始转换之前,先准备好两个缓冲区,然后将其中一个缓冲区链接到ADC和DMA。当ADC开始进行模数转换时,它将连续地将数据存储到当前链接的缓冲区。同时,DMA控制器从另一个缓冲区中读取数据,并将其发送到指定的存储区域。 当DMA传输完成时,它会触发一个中断来通知处理器数据已经准备好,并且可以进行下一步操作(例如处理数据、存储或其他数据处理任务)。同时,DMA自动将其源和目标缓冲区切换,使得ADC可以将新的转换数据存储到不同的缓冲区中,而DMA同时从旧的缓冲区中读取数据。 这种双缓冲模式可以显著提高数据转换的可靠性和效率。它可以最大限度地减少数据丢失或错位,并且保持DMA和处理器的高效率运行。需要注意的是,双缓冲模式要求应用程序在处理数据时需要充分的时间,以避免超时或数据重叠的问题。 总的来说,STM32的ADC DMA双缓冲技术为实时数据采集应用提供了一种可靠的解决方案,并且能够提高系统性能和效率。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值