0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

基于STM32定时器的DMA BURST传输为什么实现不了呢?

茶话MCU 来源:茶话MCU 2023-05-05 09:37 次阅读

有人使用STM32F4系列开发产品,程序运行过程中需要不时地对外输出一串驱动脉冲,并要求这几串脉冲的频率可变、占空比固定。他想到使用基于STM32定时器DMA BURST传输。具体点说,他期望不时地通过TIM3的CH1输出一串频率可变、占空比固定的脉冲然后停下来。这个思路在原理上是没问题的,可是他在测试过程中发现怎么也折腾不出预期的效果。

他目前使用的芯片是STM32F401,虽有点老旧,但我查看了手册,确认该芯片的TIM3是支持基于TIMER事件实现TIME寄存器与内存间的DMA BURST传输的。即每个TIMER事件可以申请多个DMA请求从而实现定时器寄存器与内存间的批量数据传输。要知某个STM32 TIMER是否支持上述功能,只需查看STM32参考手册的相关定时器的寄存器中有无TIMx_DCR和TIMx_DMAR寄存器的介绍。

1add2fa6-eae4-11ed-90ce-dac502259ad0.png

既然支持,为什么实现不了呢?关于这个功能我们还需要注意几点:

1、所选择的TIMER必须支持基于定时器事件的DMABURST传输功能。

2、触发事件必须是来自参与DMA传输的定时器事件,不能是别的定时器事件。比方说你想实现TIM1的寄存器与内存间的DMA BURST传输,触发事件不能是来自TIM2、TIM3这些非TIM1的事件。

3、定时器DMA Burst传输时,用来被BURST访问的定时器寄存器应该是同一定时器的而且是地址连续的寄存器,不可跳跃访问。比方说像下面某TIMER的4个比较寄存器物理地址是安排在一起的,而CH2恰好因为某些原因没有被用上。

1af4b5cc-eae4-11ed-90ce-dac502259ad0.png

如果你仅对CH1/CH3/CH4三个通道的比较寄存器的值做BURST访问,此时尽管CH2没有被用上,BURST访问的传输个数应该是4而不是3。

4、STM32 HAL库里的例程或函数重点在演示相应的功能或特性,但它不能包罗万象或保证适用于任何场景。有些时候我们可能需要在现有库函数的前提下适当地做些调整来满足需求。

结合这几点,我们一起排查下。第1点、第2点已经核对过了,没问题。看看第3点,即设置BURST传输个数。下图是F40x系列TIM2~TIM5的内存地址映射图。

1b166244-eae4-11ed-90ce-dac502259ad0.png

现在使用者真正需要用到的寄存器只有TIM3->ARR和TIM3->CCR1两个寄存器,但二者中间还有个预留空位【其它高级定时器的RCR寄存器的位置】也必须算进来,即这里BURST传输个数应该是3而不是2。

再看看上面提到的第4点要注意的地方。这点我就不过多解释了,ST提供的HAL库例程及相关函数只能实现1次BURST传输的功能,如果要实现多次BURST传输就得在其代码基础上做些调整,更多细节可以参考我之前分享的那篇《STM32定时器BURST传输介绍及示例》。不过,在那篇的演示例程里我使用的是DMA Circular模式,现在的用户则要使用DMA Normal模式。采用Normal模式和采用Circular模式基于现有HAL库函数组织代码还略有差异,若没处理好这点小差异,可能让你完全出不来想要的结果。

下面我使用STM32G4芯片的TIM3-CH1演示上面用户的功能。每次输出5个脉冲,3次输出为一个循环,同一循环中的3次输出的频率各不相同,占空比一样。【为什么没用STM32F401芯片,是因为此时手上没有带该芯片的开发板。不过演示功能的配置及代码基本一样。】

我使用CubeMx对TIM3进行配置,参考配置如下:

1b38b06a-eae4-11ed-90ce-dac502259ad0.png

开启TIM3基于更新事件的DMA传输功能并做相关配置。

1b62f14a-eae4-11ed-90ce-dac502259ad0.png

配置完成,生成初始化工程,添加用户代码。

我准备了3串脉冲的ARR/CCR1的值,分别以数组PulseData1[]、PulseData2[]、PulseData3[]来存放,占空比都设置为50%。显然数组行中间的0值用于前面提到过的预留字,此处无实际作用。另外,每个数组中的第6行数据其实是关闭当前通道PWM输出,具体应用时注意结合所选择的PWM模式及极性选择。

下面是参考用户代码。代码在手机模式下可左右滑动。

/* USER CODE BEGIN PD */
#define ARR1 (10000U)
#define ARR2 (20000U)
#define ARR3 (40000U)
#defineCount(18)   //3 * 6


uint16_t PulseData1[]={
 ARR1,0,ARR1*0.5,
 ARR1,0,ARR1*0.5,
 ARR1,0,ARR1*0.5,
 ARR1,0,ARR1*0.5,
 ARR1,0,ARR1*0.5,//
 ARR1,0,0};




uint16_t PulseData2[]={
ARR2,0,ARR2*0.5,
ARR2,0,ARR2*0.5,
ARR2,0,ARR2*0.5,
ARR2,0,ARR2*0.5,
ARR2,0,ARR2*0.5,//
ARR2,0,0,
};


uint16_t PulseData3[]={
ARR3,0,ARR3*0.5,
ARR3,0,ARR3*0.5,
ARR3,0,ARR3*0.5,
ARR3,0,ARR3*0.5,
ARR3,0,ARR3*0.5,//5
ARR3,0,0,
};


/* USER CODE END PD */

主循环测试代码如下:

int main(void)
{
/* USER CODE BEGIN 1 */


/* USER CODE END 1 */


/* MCU Configuration--------------------------------------------------------*/


/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();


/* USER CODE BEGIN Init */


/* USER CODE END Init */


/* Configure the system clock */
  SystemClock_Config();


/* USER CODE BEGIN SysInit */


/* USER CODE END SysInit */


/* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_DMA_Init();
  MX_TIM3_Init();
/* USER CODE BEGIN 2 */
    __HAL_TIM_CLEAR_FLAG(&htim3,TIM_FLAG_UPDATE);
  TIM_CCxChannelCmd(TIM3,TIM_CHANNEL_1,TIM_CCx_ENABLE);
/* USER CODE END 2 */


/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
  {
/* USER CODE END WHILE */


/* USER CODE BEGIN 3 */
htim3.DMABurstState=HAL_DMA_BURST_STATE_READY;
       hdma_tim3_up.State = HAL_DMA_STATE_READY ;


       __HAL_TIM_CLEAR_FLAG(&htim3,TIM_FLAG_UPDATE);


      HAL_TIM_DMABurst_MultiWriteStart(&htim3, TIM_DMABASE_ARR,TIM_DMA_UPDATE,(uint32_t *)PulseData1,
                                       TIM_DMABURSTLENGTH_3TRANSFERS,Count);
      TIM3->EGR = TIM_EGR_UG;
      __HAL_TIM_ENABLE(&htim3);


HAL_Delay(150);//Preparedforthe next5 Pulses
__HAL_TIM_DISABLE(&htim3);
//  HAL_DMA_Abort(&hdma_tim3_up);


      htim3.DMABurstState = HAL_DMA_BURST_STATE_READY;
      hdma_tim3_up.State = HAL_DMA_STATE_READY ;


      __HAL_TIM_CLEAR_FLAG(&htim3,TIM_FLAG_UPDATE);


       HAL_TIM_DMABurst_MultiWriteStart(&htim3, TIM_DMABASE_ARR,TIM_DMA_UPDATE,(uint32_t *)PulseData2,
                                        TIM_DMABURSTLENGTH_3TRANSFERS,Count);
      TIM3->EGR = TIM_EGR_UG;
      __HAL_TIM_ENABLE(&htim3);


      HAL_Delay(150);//Prepared for the next 5 Pulses
__HAL_TIM_DISABLE(&htim3);
//   HAL_DMA_Abort(&hdma_tim3_up);


      htim3.DMABurstState = HAL_DMA_BURST_STATE_READY;
      hdma_tim3_up.State = HAL_DMA_STATE_READY ;


       __HAL_TIM_CLEAR_FLAG(&htim3,TIM_FLAG_UPDATE);


       HAL_TIM_DMABurst_MultiWriteStart(&htim3, TIM_DMABASE_ARR,TIM_DMA_UPDATE,(uint32_t *)PulseData3,
                                        TIM_DMABURSTLENGTH_3TRANSFERS,Count);
      TIM3->EGR = TIM_EGR_UG;
      __HAL_TIM_ENABLE(&htim3);


      HAL_Delay(150);//Prepared for the next 5 Pulses
__HAL_TIM_DISABLE(&htim3);
//   HAL_DMA_Abort(&hdma_tim3_up);


  }
/* USER CODE END 3 */
}

编译、除错后,运行程序可以看到我所期望的结果。即我每隔一会儿就发出5个脉冲,3次为1个循环。测试代码都放在这里,供参考使用。这里不逐句解释了,具体使用时结合库代码来研究即可。

1b779136-eae4-11ed-90ce-dac502259ad0.png

最后,补充一下有关上篇《利用非对称PWM模式体验编码器功能》文中3个变量如何使用ARM MDK IDE自带逻辑分析仪的配置,我把配置截图放于此供有需要的人参考。

这里的CNT_value连续记录TIM2计数器的值,这里为Analog量。

Level_PA8记录GPIOA_PIN8的电平情况,1或0两个值之一,为Bit量。

Level_PA9跟Level_PA8是完全相同的数据类型,显示的是GPIOA_PIN9的电平。显然,逻辑分析仪配置里关于Level_PA9的显示算式的屏蔽数应该是0x00000200,右移位为9。我是在SYSTICK的毫秒中断里读取GPIOA->IDR的值即管脚电平到变量Level_PA8和Level_PA9的。【下图中Core Clock填写芯片支持的最高主频】

1b8f5686-eae4-11ed-90ce-dac502259ad0.png

1ba57cfe-eae4-11ed-90ce-dac502259ad0.png







审核编辑:刘清

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 寄存器
    +关注

    关注

    30

    文章

    5031

    浏览量

    117736
  • 定时器
    +关注

    关注

    23

    文章

    3148

    浏览量

    112040
  • dma
    dma
    +关注

    关注

    3

    文章

    535

    浏览量

    99027
  • STM32F4
    +关注

    关注

    3

    文章

    192

    浏览量

    27678

原文标题:为何实现不了定时器DMA Burst传输?

文章出处:【微信号:stmcu832,微信公众号:茶话MCU】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    STM32F103定时器触发ADC+DMA传输 精选资料分享

    STM32F103定时器触发ADC+DMA传输ADC除了软件触发方式之外还有外部触发模式,我用TIM2定时器触发ADC,并用
    发表于 08-11 06:05

    如何去实现STM32定时器US级的延时

    STM32定时器可分为哪几类?STM32定时器的结构是由哪些部分组成的?如何去实现STM32
    发表于 11-09 06:30

    TIMx“DMA Burst Feature”如何通过SPI触发多个DMA请求?

    ,因为 SPI 外设最多支持 16 位传输。不过,我还没有看到有人使用 Timer DMA-burst 功能。我想使用计时来触发 DMA/SPI
    发表于 02-07 08:23

    STM32F030的定时器PWM使用设置与ADC的dma代码

    里面是STM32F030的定时器PWM使用设置与ADC的dma代码
    发表于 03-21 15:29 151次下载

    基于STM32定时器实现毫秒延时函数

    STM32定时器包含基本定时器、通用定时器和高级定时器,其中TIM6和TIM7是STM32当中的
    发表于 10-12 15:54 2.5w次阅读
    基于<b class='flag-5'>STM32</b><b class='flag-5'>定时器</b><b class='flag-5'>实现</b>毫秒延时函数

    STM32定时器触发DMA数据传输失败的原因如何解决

    有人使用STM32定时器事件触发DMA,让其将内存数据传输到通信外设的数据寄存器进行发送,发现DMA根本就不动作。
    的头像 发表于 11-25 09:21 2w次阅读
    <b class='flag-5'>STM32</b><b class='flag-5'>定时器</b>触发<b class='flag-5'>DMA</b>数据<b class='flag-5'>传输</b>失败的原因如何解决

    定时器实现3路时差和占空比可调的波形

    这里使用STM32F302_Nucleo板来实现之。使用STM32常规定时器中的高级定时器TIM1来实现
    的头像 发表于 11-20 14:54 3592次阅读
    <b class='flag-5'>定时器</b><b class='flag-5'>实现</b>3路时差和占空比可调的波形

    STM32定时器BURST传输介绍及示例

    这里有两个专门用于定时器BURST传输的寄存器,分别是TIM2_DCR和TIM2_DMAR. 其中TIM2_DCR就是用来配置从哪个定时器寄存器开始访问、连续访问几个寄存器的问题。
    的头像 发表于 05-14 09:15 1.1w次阅读
    <b class='flag-5'>STM32</b><b class='flag-5'>定时器</b><b class='flag-5'>BURST</b><b class='flag-5'>传输</b>介绍及示例

    基于STM32定时器捕获测量脉宽的应用示例

    我们知道,利用单片机定时器捕获功能测量脉冲信号宽度及占空比是种很常见的做法。这里以STM32定时器为例来介绍基于其捕获功能实现对脉宽的测量的思路及过程。 一般来讲,使用
    的头像 发表于 01-02 18:17 1.2w次阅读
    基于<b class='flag-5'>STM32</b><b class='flag-5'>定时器</b>捕获测量脉宽的应用示例

    STM32CUBEMX配置教程(十二)STM32定时器触发的固定频率ADC采样(使用DMA

    STM32CUBEMX配置教程(十二)STM32定时器触发的固定频率ADC采样(使用DMA
    发表于 11-24 13:51 83次下载
    <b class='flag-5'>STM32</b>CUBEMX配置教程(十二)<b class='flag-5'>STM32</b>的<b class='flag-5'>定时器</b>触发的固定频率ADC采样(使用<b class='flag-5'>DMA</b>)

    STM32CUBEMX配置教程(十三)STM32定时器触发的固定频率DAC输出(使用DMA

    STM32CUBEMX配置教程(十三)STM32定时器触发的固定频率DAC输出(使用DMA
    发表于 11-24 14:06 44次下载
    <b class='flag-5'>STM32</b>CUBEMX配置教程(十三)<b class='flag-5'>STM32</b>的<b class='flag-5'>定时器</b>触发的固定频率DAC输出(使用<b class='flag-5'>DMA</b>)

    STM32F103定时器触发ADC+DMA传输

    STM32F103定时器触发ADC+DMA传输ADC除了软件触发方式之外还有外部触发模式,我用TIM2定时器触发ADC,并用
    发表于 11-30 10:36 50次下载
    <b class='flag-5'>STM32</b>F103<b class='flag-5'>定时器</b>触发ADC+<b class='flag-5'>DMA</b><b class='flag-5'>传输</b>

    H743定时器触发ADC转换DMA传输之应用

    学习安富莱的H743的定时器触发ADC DMA传输源码
    发表于 11-30 11:21 11次下载
    H743<b class='flag-5'>定时器</b>触发ADC转换<b class='flag-5'>DMA</b><b class='flag-5'>传输</b>之应用

    stm32 定时器触发ADC多通道采样+DMA提取数据

    stm32g0 定时器触发ADC多通道采样+DMA提取数据stm32g0 定时器触发ADC多通道采样+D
    发表于 12-16 16:56 64次下载
    <b class='flag-5'>stm32</b> <b class='flag-5'>定时器</b>触发ADC多通道采样+<b class='flag-5'>DMA</b>提取数据

    定时器DMA Burst传输无法实现

    有人使用STM32F4系列开发产品,程序运行过程中需要不时地对外输出一串驱动脉冲,并要求这几串脉冲的频率可变、占空比固定。他想到使用基于STM32定时器DMA
    的头像 发表于 06-21 16:21 556次阅读
    <b class='flag-5'>定时器</b><b class='flag-5'>DMA</b> <b class='flag-5'>Burst</b><b class='flag-5'>传输</b>无法<b class='flag-5'>实现</b>