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

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

3天内不再提示

使用MM32F0270 定时器DMA方式输出PWM

jf_pJlTbmA9 来源:灵动MM32MCU 作者:灵动MM32MCU 2023-10-17 14:47 次阅读

对于控制步进电机来说,最重要的控制参数是脉冲的数量和频率,两者结合可以实现满足要求的电机加减速曲线。在一些电机应用数量不多的场合,通常使用定时器中断发送脉冲来控制步进电机,优点是原理简单代码易于实现。但是一旦控制的电机多起来,就会占用大量的MCU资源,这在大多数情况下是不可接受的,更不用说多轴联动了。那么如何做到占用很少的MCU资源,又能实现脉冲发送的精确控制?

于是就想到了使用DMA功能更新PWM的输出, DMA全称Direct Memory Access,即直接存储器访问。DMA传输将数据从一个地址空间复制到另一个地址空间,提供在外设和存储器之间或者存储器和存储器之间的高速数据传输。它允许不同速度的硬件装置来沟通,而不需要依赖于MPU的大量中断负载。

通过设置DMA传输数据的数量,可以控制发送的脉冲数。通过设置不同的装载值和顺序,可以使用不同频率和脉宽。当需要发送较多数量的脉冲时,则可以使用DMA传输完成中断中切换DMA传输的数据起始地址及发送数量,继续发送。这个方法即方便,又减轻MPU的负担,可以同时驱动多个电机工作,还可以根据电机的启动、运行、停止使用不同的频率。

定时器DMA模式

MM32F0270的定时器TIM1、TIM2、TIM3、TIM15、TIM16/17有DMA模式,能够在发生单个事件时生成多个DMA 请求。主要目的是在没有软件开销的情况下,多次重新编程定时器的一部分,也可以用于按周期读取数个寄存器。下面以TIM1为例介绍:

TIM1_DCR 和 TIM1_DMAR 寄存器跟 DMA 模式相关。DMA 控制器的目标是唯一的,必须指向TIM1_DMAR 寄存器。开启 DMA 使能后,在给定的 TIM1 事件发生时, TIM1 会给 DMA 发送请求。

对 TIM1_DMAR 寄存器的每次写操作都被重定向到一个 TIM1 寄存器。TIM1_DCR寄存器的DBL位定义了DMA连续传送的长度,即传输寄存器数量;当对TIM1_DMAR进行读写操作时,定时器识别 DBL,确定传输的寄存器数量。TIM1_DCR 寄存器的 DBA 位定义了DMA 传输的基地址, 定义从 TIM1_CR1 寄存器地址开始的偏移量(00000 为 TIM1_CR1;00001 为TIM1_CR2;……; 00110 为 TIM1_CCMR1 等)。

通过定时器的DMA模式来更新PWM,本文参官网例程“TIM1_DMA_UPData”进行说明具体实现方法。

实验

本实验使用TIM1的DMA模式,当更新事件发生时,更新 TIM1_CCR1、TIM1_CCR2 和 TIM1_CCR3 寄存器的内容。程序中配置TIM1的通道1、通道2、通道3输出PWM,再通过DMA搬运数据来改变PWM的占空比。定时器每产生一个溢出事件(即计数完成),就发送DMA请求,根据数据在数组中的排列顺序以生成所需要的时序。

程序部分

GPIO初始化

配置TIM1_CH1、TIM1_CH2 和 TIM1_CH3对应的GPIO。

void TIM1_GPIO_Init(void)
{
    GPIO_InitTypeDef GPIO_InitStruct;
    RCC_AHBPeriphClockCmd(RCC_AHBENR_GPIOA, ENABLE);
    GPIO_PinAFConfig(GPIOA, GPIO_PinSource8, GPIO_AF_2);
    GPIO_PinAFConfig(GPIOA, GPIO_PinSource9, GPIO_AF_2);
    GPIO_PinAFConfig(GPIOA, GPIO_PinSource10, GPIO_AF_2);
    GPIO_InitStruct.GPIO_Pin = GPIO_Pin_8 | GPIO_Pin_9 | GPIO_Pin_10;
    GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP;
    GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOA,  GPIO_InitStruct);
}

TIM1 DMA初始化

TIM1_CH3对应DMA1通道5,将data[]中的数据传送到TIM1_DMAR寄存器,传输方向从存储器到外设,数据宽度为半字,使能DMA传输完成中断。

void TIM_DMA_Init(void)
{
    DMA_InitTypeDef  DMA_InitStruct;

    RCC_AHBPeriphClockCmd(RCC_AHBENR_DMA1, ENABLE);

    DMA_DeInit(DMA1_Channel5);
    DMA_StructInit( DMA_InitStruct);
    //Transfer register address
    DMA_InitStruct.DMA_PeripheralBaseAddr    = (u32)   (TIM1->DMAR);
    //Transfer memory address
    DMA_InitStruct.DMA_MemoryBaseAddr        = (u32)data;
    //Transfer direction, from memory to register
    DMA_InitStruct.DMA_DIR                   = DMA_DIR_PeripheralDST;
    DMA_InitStruct.DMA_BufferSize            = 6;
    DMA_InitStruct.DMA_PeripheralInc         = DMA_PeripheralInc_Disable;
    //Transfer completed memory address increment
    DMA_InitStruct.DMA_MemoryInc             = DMA_MemoryInc_Enable;
    DMA_InitStruct.DMA_PeripheralDataSize    = DMA_PeripheralDataSize_HalfWord;
    DMA_InitStruct.DMA_MemoryDataSize        = DMA_MemoryDataSize_HalfWord;
    DMA_InitStruct.DMA_Mode                  = DMA_Mode_Circular;
    DMA_InitStruct.DMA_Priority              = DMA_Priority_High;
    DMA_InitStruct.DMA_M2M                   = DMA_M2M_Disable;
    DMA_InitStruct.DMA_Auto_reload = DMA_Auto_Reload_Disable;
    DMA_Init(DMA1_Channel5,  DMA_InitStruct);

    DMA_ITConfig(DMA1_Channel5, DMA_IT_TC, ENABLE);

}

TIM1 PWM初始化

TIM1输出PWM,配置时钟分频系数和预装载值,递增计数,使用PWM模式1,输出高电平有效,分别对TIM1_CH1、TIM1_CH2、TIM1_CH3指定要加载到捕获比较寄存器中的脉冲值为arr/2、arr/4、arr/6,使能TIM1的DMA模式,起始地址为TIM1_CCR1,传输长度为3。

void TIM1_PWM_Init(u16 arr, u16 psc)
{
    TIM_TimeBaseInitTypeDef  TIM_TimeBaseStruct;
    TIM_OCInitTypeDef  TIM_OCInitStruct;

    RCC_APB2PeriphClockCmd(RCC_APB2ENR_TIM1, ENABLE);

    TIM_TimeBaseStructInit( TIM_TimeBaseStruct);
    TIM_TimeBaseStruct.TIM_Period = arr;
    TIM_TimeBaseStruct.TIM_Prescaler = psc;
    //Setting Clock Segmentation
    TIM_TimeBaseStruct.TIM_ClockDivision = TIM_CKD_DIV1;
    TIM_TimeBaseStruct.TIM_RepetitionCounter = 0;
    ///TIM Upward Counting Mode
    TIM_TimeBaseStruct.TIM_CounterMode = TIM_CounterMode_Up;
    TIM_TimeBaseInit(TIM1,  TIM_TimeBaseStruct);

    TIM_OCStructInit( TIM_OCInitStruct);
    //Select Timer Mode: TIM Pulse Width Modulation Mode 2
    TIM_OCInitStruct.TIM_OCMode = TIM_OCMode_PWM1;
    TIM_OCInitStruct.TIM_OutputState = TIM_OutputState_Enable;
    TIM_OCInitStruct.TIM_OCPolarity = TIM_OCPolarity_High;

    //Setting the Pulse Value of the Capture Comparison Register to be Loaded
    TIM_OCInitStruct.TIM_Pulse = arr / 2;
    TIM_OC1Init(TIM1,  TIM_OCInitStruct);
    TIM_OC3PreloadConfig(TIM1, TIM_OCPreload_Enable);

    TIM_OCInitStruct.TIM_Pulse = arr / 4;
    TIM_OC2Init(TIM1,  TIM_OCInitStruct);
    TIM_OC2PreloadConfig(TIM1, TIM_OCPreload_Enable);

    TIM_OCInitStruct.TIM_Pulse = arr / 6;
    TIM_OC3Init(TIM1,  TIM_OCInitStruct);
    TIM_OC3PreloadConfig(TIM1, TIM_OCPreload_Enable);

    TIM_ARRPreloadConfig(TIM1, ENABLE);

    TIM_DMAConfig(TIM1, TIM_DMABase_CCR1, TIM_DMABurstLength_3Bytes);
    TIM_DMACmd(TIM1, TIM_DMA_Update, ENABLE);
    TIM_CtrlPWMOutputs(TIM1, ENABLE);

    TIM_Cmd(TIM1, ENABLE);
}

使能DMA1通道5

DMA_Cmd(DMA1_Channel5, ENABLE);

配置NVIC

NVIC_Configure(DMA1_Channel4_5_6_7_IRQn, 1, 1);

DMA1中断服务子程序

void DMA1_Channel4_5_6_7_IRQHandler()
{
    if (DMA_GetITStatus(DMA1_IT_TC5)) {
        //clear IRQ flag
        DMA_ClearITPendingBit(DMA1_IT_TC5);
    }
}

定义数组data[]

static u16 data[] = {2000, 3000, 4000, 8000, 7000, 6000};

Main()函数

s32 main(void)
{
    TIM1_GPIO_Init();
    TIM1_PWM_Init(10000, 0);
    TIM_DMA_Init();
    NVIC_Configure(DMA1_Channel4_5_6_7_IRQn, 1, 1);
    DMA_Cmd(DMA1_Channel5, ENABLE);
    while (1) {
    }
}

演示

下载程序到目标板。连接逻辑分析仪测试PA8、PA9、PA10的输出,打开对应上位机软件启动采样,运行程序,各通道的PWM输出情况如下:

wKgaomUD772AHrmCAACIeLDRj7Q290.png

截取其中1个周期观察:

wKgZomUD776ADUH5AADZEUJrwpQ251.png

TIM1_CH1输出PWM占空比为20%和80%, TIM1_CH1输出PWM占空比为30%和70%, TIM1_CH1输出PWM占空比为40%和60%,运行结果和预期一致。

实验简单演示了MM32F0270的定时器TIM1的DMA方式更新PWM,通过该方案可以实现多路、不同频率、不同脉宽、数量精确可控的PWM波。

工程路径如下:

~ MM32FMM32F0270_Lib_SamplesMM32F0270_SamplesLibSamplesTIMTIM1_DMA_UPData。

来源:灵动MM32MCU
免责声明:本文为转载文章,转载此文目的在于传递更多信息,版权归原作者所有。本文所用视频、图片、文字如涉及作品版权问题,请联系小编进行处理

审核编辑 黄宇

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

    关注

    114

    文章

    5186

    浏览量

    213826
  • 定时器
    +关注

    关注

    23

    文章

    3246

    浏览量

    114742
  • dma
    dma
    +关注

    关注

    3

    文章

    561

    浏览量

    100554
收藏 人收藏

    评论

    相关推荐

    灵动微课堂 (第196讲) | 使用MM32F0270 LPTIM从STOP模式唤醒

    LED灯。01 MM32F0270 LPTIM的简要介绍LPTIM即低功耗定时器,得益于其定时器的低功耗。由于 LPTIM 的时钟源具有多样性,因此 LPTIM 能够在所有电源模式(待机模式除外)下保持
    发表于 01-10 11:38

    灵动微课堂 (第197讲) | MM32F0270 UART空闲中断 + DMA接收不定长数据

    )UART DMA方式MM32F0270 UART使用DMA方式接收数据可以减小CPU的开销。对于接收定长数据,可以将
    发表于 01-10 11:42

    灵动微课堂 (第198讲) | 使用MM32F0270 LPUART从低功耗模式唤醒

    在许多的工业与消费类应用中,越来越多的需要使用低功耗功能,使用外部串口数据通信发送命令来唤醒MCU。灵动微电子推出的MM32F0270系列,支持多种灵活的低功耗模式,支持LPUART的外设。本文介绍
    发表于 01-17 13:24

    灵动微课堂 (第200讲) | 使用MM32F0270 定时器DMA方式输出PWM

    %, TIM1_CH1输出PWM占空比为40%和60%,运行结果和预期一致。实验简单演示了MM32F0270定时器TIM1的DMA
    发表于 02-18 13:36

    灵动微课堂 (第200讲) | 使用MM32F0270 定时器DMA方式输出PWM

    PWM占空比为20%和80%, TIM1_CH1输出PWM占空比为30%和70%, TIM1_CH1输出PWM占空比为40%和60%,运行结
    发表于 03-17 17:26

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

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

    MM32F0140定时器模块计数定时功能

    本篇笔记主要探讨 MM32F0140 定时器模块的框图结构、定时器提供的计数定时等功能以及配置定时器的流程,并以 pokt-
    的头像 发表于 04-07 16:31 2759次阅读
    <b class='flag-5'>MM32F</b>0140<b class='flag-5'>定时器</b>模块计数<b class='flag-5'>定时</b>功能

    MM32F0270 产品手册(中文版)

    MM32F0270 产品手册(中文版)
    发表于 02-23 18:36 0次下载
    <b class='flag-5'>MM32F0270</b> 产品手册(中文版)

    MM32F0270 产品手册(英文版)

    MM32F0270 产品手册(英文版)
    发表于 02-23 18:37 0次下载
    <b class='flag-5'>MM32F0270</b> 产品手册(英文版)

    MM32F0270 用户手册(中文版)

    MM32F0270 用户手册(中文版)
    发表于 02-23 18:37 0次下载
    <b class='flag-5'>MM32F0270</b> 用户手册(中文版)

    MM32F0270 用户手册(英文版)

    MM32F0270 用户手册(英文版)
    发表于 02-23 18:38 0次下载
    <b class='flag-5'>MM32F0270</b> 用户手册(英文版)

    MM32F0270 勘误表(中文版)

    MM32F0270 勘误表(中文版)
    发表于 02-23 18:38 0次下载
    <b class='flag-5'>MM32F0270</b> 勘误表(中文版)

    MM32F0270 勘误表(英文版)

    MM32F0270 勘误表(英文版)
    发表于 02-23 18:39 0次下载
    <b class='flag-5'>MM32F0270</b> 勘误表(英文版)

    使用MM32F0270 USB从Suspend模式唤醒

    使用MM32F0270 USB从Suspend模式唤醒
    的头像 发表于 09-26 16:39 955次阅读
    使用<b class='flag-5'>MM32F0270</b> USB从Suspend模式唤醒

    使用MM32F0270 LPTIM从STOP模式唤醒

    使用MM32F0270 LPTIM从STOP模式唤醒
    的头像 发表于 10-26 16:46 997次阅读
    使用<b class='flag-5'>MM32F0270</b> LPTIM从STOP模式唤醒