STM32F4 -- How to use the DMA burst feature

本文详细介绍了STM32 DMA突发传输机制的原理、配置步骤及应用示例,包括DBL、DBA、DMAB等关键参数的作用及使用方法,通过实例演示如何利用DMA突发特性更新CCRx寄存器内容。

Bits 15:13 Reserved, must be kept at reset value.

Bits 12:8 DBL[4:0]: DMA burst length

This 5-bit vector defines the number of DMA transfers

(the timer detects a burst transfer when a read or a write access to the TIMx_DMAR register address is performed).

  • 00000: 1 transfer
  • 00001: 2 transfers
  • 00010: 3 transfers
  • ...
  • 10001: 18 transfers

Bits 7:5 Reserved, must be kept at reset value.

Bits 4:0 DBA[4:0]: DMA base address

This 5-bits vector defines the base-address for DMA transfers (when read/write access are done through the TIMx_DMAR address).

DBA is defined as an offset starting from the address of the TIMx_CR1 register.

Example:

  • 00000: TIMx_CR1,
  • 00001: TIMx_CR2,
  • 00010: TIMx_SMCR,

...


Example: Let us consider the following transfer: DBL = 7 transfers and DBA = TIMx_CR1.

In this case the transfer is done to/from 7 registers starting from the TIMx_CR1 address.

 

Bits 15:0 DMAB[15:0]: DMA register for burst accesses


A read or write operation to the DMAR register accesses the register located at the address 

(TIMx_CR1 address) + (DBA + DMA index) x 4

DBA is defined as an offset starting from the address of the TIMx_CR1 register.

where TIMx_CR1 address is the address of the control register 1,

DBA is the DMA base address configured in TIMx_DCR register,

DMA index is automatically controlled by the DMA transfer,

and ranges from 0 to DBL (DBL configured in TIMx_DCR).

DBL This 5-bit vector defines the number of DMA transfers

Example of how to use the DMA burst feature

In this example the timer DMA burst feature is used to update the contents of the CCRx registers (x = 2, 3, 4)

with the DMA transferring half words into the CCRx registers.

This is done in the following steps:

1. Configure the corresponding DMA channel as follows:
– DMA channel peripheral address is the DMAR register address
– DMA channel memory address is the address of the buffer in the RAM
   containing the data to be transferred by DMA into CCRx registers.
Number of data to transfer = 3 (See note below).: CCR2, CCR3, CCR4
– Circular mode disabled.

2. Configure the DCR register by configuring the DBA and DBL bit fields as follows:
DBL = 3 transfers, DBA = 0xE. :: 4 * 0x0E = 0x38

3. Enable the TIMx update DMA request (set the UDE bit in the DIER register).

4. Enable TIMx

5. Enable the DMA channel

Note:

This example is for the case where every CCRx register to be updated once.

Let's take the example of a buffer in the RAM containing data1, data2, data3.

The data is transferred to the CCRx registers as follows:

on the update DMA request, data1 is transferred to CCR2, data2 is transferred to CCR3, data3 is transferred to CCR4 and

 

 

If every CCRx register is to be updated twice for example, the number of data to transfer should be 6 -- DMA

NumberOfTransfer = UpdateTimes * DMA burst length<DBL>.

Let's take the example of a buffer in the RAM containing data1, data2, data3, data4, data5 and data6.

The data is transferred to the CCRx registers as follows:

on the first update DMA request, data1 is transferred to CCR2, data2 is transferred to CCR3, data3 is transferred to CCR4 and

on the second update DMA request, data4 is transferred to CCR2, data5 is transferred to CCR3 and data6 is transferred to CCR4.

 

/**
  ******************************************************************************
  * @file    TIM/TIM_DMABurst/main.c 
  * @author  MCD Application Team
  * @version V1.1.0
  * @date    18-January-2013
  * @brief   Main program body
  ******************************************************************************
  * @attention
  *
  * <h2><center>&copy; COPYRIGHT 2013 STMicroelectronics</center></h2>
  *
  * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License");
  * You may not use this file except in compliance with the License.
  * You may obtain a copy of the License at:
  *
  *        http://www.st.com/software_license_agreement_liberty_v2
  *
  * Unless required by applicable law or agreed to in writing, software 
  * distributed under the License is distributed on an "AS IS" BASIS, 
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
  *
  ******************************************************************************
  */

/* Includes ------------------------------------------------------------------*/
#include "main.h"

/** @addtogroup STM32F4xx_StdPeriph_Examples
  * @{
  */

/** @addtogroup TIM_DMABurst
  * @{
  */ 

/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
#define TIM1_DMAR_ADDRESS ((uint32_t)0x4001004C) /* TIM DMAR address */

/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
GPIO_InitTypeDef         GPIO_InitStructure;
DMA_InitTypeDef          DMA_InitStructure;
TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
TIM_OCInitTypeDef        TIM_OCInitStructure;

uint16_t aSRC_Buffer[6] = {0x0FFF, 0x0000, 0x0555}; // APR, RCR, CCR1

/* Private function prototypes -----------------------------------------------*/
static void TIM_Config(void);

/* Private functions ---------------------------------------------------------*/

/**
  * @brief  Main program
  * @param  None
  * @retval None
  */
int main(void)
{
  /*!< At this stage the microcontroller clock setting is already configured, 
       this is done through SystemInit() function which is called from startup
       files (startup_stm32f40xx.s/startup_stm32f427x.s) before to branch to 
       application main. 
       To reconfigure the default setting of SystemInit() function, refer to
       system_stm32f4xx.c file
     */     

  /* TIM1 Configuration */
  TIM_Config();       
  
  /* Time base configuration */
  /* -----------------------------------------------------------------------
    TIM1 Configuration: generate 1 PWM signal using the DMA burst mode:
  
    TIM1 input clock (TIM1CLK) is set to 2 * APB2 clock (PCLK2), since APB2 prescaler is different from 1.   
      TIM1CLK = 2 * PCLK2, PCLK2 = HCLK / 2 => TIM1CLK = 2 * (HCLK / 2) = HCLK = SystemCoreClock
    
    To get TIM1 counter clock at 24 MHz, the prescaler is computed as follows:
      Prescaler = (TIM1CLK / TIM1 counter clock) - 1
      Prescaler = (SystemCoreClock /24 MHz) - 1
  
    The TIM1 period is 5.8 KHz: 
TIM1 Frequency = TIM1 counter clock/(ARR + 1) = 24 MHz / 4096 = 5.85 KHz TIM1 Channel1 duty cycle = (TIM1_CCR1/ TIM1_ARR)* 100 = 33.33% Note: SystemCoreClock variable holds HCLK frequency and is defined in system_stm32f4xx.c file. Each time the core clock (HCLK) changes, user had to call SystemCoreClockUpdate() function to update SystemCoreClock variable value. Otherwise, any configuration based on this variable will be incorrect. -----------------------------------------------------------------------
*/ TIM_TimeBaseStructure.TIM_Period = 0xFFFF; TIM_TimeBaseStructure.TIM_Prescaler = (uint16_t) (SystemCoreClock / 24000000) - 1; TIM_TimeBaseStructure.TIM_ClockDivision = 0x0; TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; TIM_TimeBaseInit(TIM1, &TIM_TimeBaseStructure); /* TIM Configuration in PWM Mode */ TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; TIM_OCInitStructure.TIM_Pulse = 0xFFF; TIM_OC1Init(TIM1, &TIM_OCInitStructure); /* TIM1 DMAR Base register and DMA Burst Length Config */ TIM_DMAConfig(TIM1, TIM_DMABase_ARR, TIM_DMABurstLength_3Transfers); // APR, RCR, CCR1 /* TIM1 DMA Update enable */ TIM_DMACmd(TIM1, TIM_DMA_Update, ENABLE); /* TIM1 enable */ TIM_Cmd(TIM1, ENABLE); /* TIM1 PWM Outputs Enable */ TIM_CtrlPWMOutputs(TIM1, ENABLE); /* Enable DMA2 Stream5 */ DMA_Cmd(DMA2_Stream5, ENABLE); /* Wait until DMA2 Stream5 end of Transfer */ while (!DMA_GetFlagStatus(DMA2_Stream5, DMA_FLAG_TCIF5)) { } /* Infinite loop */ while(1) { } } /** * @brief Configure the TIM1 Pins. * @param None * @retval None */ static void TIM_Config(void) { GPIO_InitTypeDef GPIO_InitStructure; /* TIM1 clock enable */ RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE); /* GPIOA clock enable */ RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE); /* DMA2 clock enable */ RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2, ENABLE); /* GPIOA Configuration: PA8(TIM1 CH1) as alternate function push-pull */ GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8; 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_NOPULL; GPIO_Init(GPIOA, &GPIO_InitStructure); /* Connect TIM pins to AF1 */ GPIO_PinAFConfig(GPIOA, GPIO_PinSource8, GPIO_AF_TIM1); /* DeInitialize the DMA2 Stream5 */ DMA_DeInit(DMA2_Stream5); DMA_InitStructure.DMA_Channel = DMA_Channel_6; // TIM1_UP : DMA2_Stream5 DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)TIM1_DMAR_ADDRESS; DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)aSRC_Buffer; DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral; DMA_InitStructure.DMA_BufferSize = 3; 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_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; DMA_Init(DMA2_Stream5, &DMA_InitStructure); } #ifdef USE_FULL_ASSERT /** * @brief Reports the name of the source file and the source line number * where the assert_param error has occurred. * @param file: pointer to the source file name * @param line: assert_param error line source number * @retval None */ void assert_failed(uint8_t* file, uint32_t line) { /* User can add his own implementation to report the file name and line number, ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */ while (1) {} } #endif /** * @} */ /** * @} */ /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

 

### STM32F4STM32F1DMA 功能差异 #### 总体架构对比 STM32F4STM32F1 都支持直接内存访问 (DMA),用于加速数据传输并减少 CPU 负载。然而,两者的 DMA 控制器设计存在显著区别。STM32F4 提供更先进的 DMA 架构,具有更多的通道数和支持的功能模式[^1]。 #### 通道数量与优先级管理 - **STM32F1**: 它配备了两个独立的 DMA 控制器(DMA1DMA2),总共提供多达 12 条通道。每条通道可以配置固定或动态优先级。 - **STM32F4**: 这款微控制器拥有单个高级 DMA 控制器,具备多达 16 条通道,并且允许更加灵活的优先级设置以及中断处理机制[^2]。 #### 数据宽度与存储器类型支持 - 对于每次传输的数据大小选项方面, -STM32F1 中, 可选字节(8位), 半字(16位) 或全字(32位)[^3]. - 相较之下, STM32F4 不仅延续这些基本单位的选择外还增加了对双字操作的支持,在某些特定应用场景下能够进一步提升效率[^4]. #### 增强特性 - **循环缓冲区管理**:两者均能实现简单的环形缓冲区功能;但是只有在更高性能版本如stm32f4系列里才引入了专门针对这种需求优化过的硬件模块——Memory-to-Memory Transfer Mode(memory to memory transfer mode),它使得无需借助外部设备即可完成复杂的内部数据搬移任务而不会干扰其他正常运行中的程序流程[^5]。 - **突发传送(Burst Transfers)**: 此项技术首次出现在stm32f4系列产品线当中,通过允许多次连续读写动作在一个单独请求周期内被执行完毕来极大地提高了带宽利用率和整体吞吐量表现水平[^6]。 ```c // Example of enabling burst transfers on STM32F4 void EnableBurstTransfer(DMA_Stream_TypeDef* Stream){ Stream->CR |= DMA_SxCR_MBURST_0; // Set Memory Burst Type as INCR4 } ``` #### FIFO 模式 另一个值得注意的区别在于 fifo buffer usage model 上面有所改进: - 当涉及到较长序列或者复杂结构化数组拷贝作业时候,利用fifo queue structure 将会变得更加高效便捷; - 特别是在 stm32f4 平台之上新增加了一个叫做 "FIFO Threshold Control Bits" 的参数设定接口,让用户可以根据实际项目情况自定义调整最佳阈值点位置从而达到最优平衡状态之间 trade-off between latency and resource consumption.[^7] ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值