打印
[应用相关]

请教香版,DMA+TIM改变PWM占空比CCR1有变化波形不变.

[复制链接]
3926|8
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
GZZXB|  楼主 | 2021-6-29 16:08 | 只看该作者 |只看大图 回帖奖励 |倒序浏览 |阅读模式
   STM32F030 PA7配置为TIM17 CH1输出PWM波, 用DMA来改变占空比.   keil仿真可以看到CCR1 在0x3FFF和0xBFFF之间改变,但是用示波器测量一直是固定输出0x3FFF占空比. 请问这是什么缘故?
    代码如下:
uint16_t Encode_Tab[4]={16383,49151,5000,880};
void ConfigRa7PwmOut(void)
{
    GPIO_InitTypeDef GPIO_InitStructure;
        //--------mcu io 设置
    GPIO_PinAFConfig(GPIOA,GPIO_PinSource7,GPIO_AF_5);     //复用位tim17_ch1
    GPIO_InitStructure.GPIO_Pin  = GPIO_Pin_7;             //TIM3是复用功能
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
    GPIO_InitStructure.GPIO_OType=GPIO_OType_PP;
    GPIO_InitStructure.GPIO_PuPd=GPIO_PuPd_NOPULL;
    GPIO_Init(GPIOA, &GPIO_InitStructure);
}

#define TIM17_DMAR_ADDRESS ((uint32_t)0x4001484C) /* TIM DMAR address */
void Timer17Config(void)
{
    ConfigRa7PwmOut();
    NVIC_InitTypeDef NVIC_InitStructure;
    TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
    // 开启定时器时钟, 即pll时钟 CK_INT=48M
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM17, ENABLE);      //使能TIM17时钟

    /*--------------------时基结构体初始化-------------------------*/

    // 自动重装载寄存器的值,累计 TIM_Period+1 个频率后产生一个更新或者中断
    TIM_TimeBaseStructure.TIM_Period=65535-1;                 //最大计数65ms
    // 驱动 CNT 计数器的时钟 = Fck_int/(psc+1)
    TIM_TimeBaseStructure.TIM_Prescaler= 48-1;                //1M
    // 时钟分频因子 ,配置死区时间时需要用到
    TIM_TimeBaseStructure.TIM_ClockDivision=TIM_CKD_DIV1;
    // 计数器计数模式,设置为向上计数
    TIM_TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Up;
    // 重复计数器的值,没用到不用管
    TIM_TimeBaseStructure.TIM_RepetitionCounter=0;
    // 初始化定时器
    TIM_TimeBaseInit(TIM17, &TIM_TimeBaseStructure);

    /*--------------------结构体初始化-------------------*/
    TIM_OCInitTypeDef TIM_OCInitStructure;
    TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
    TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
    TIM_OCInitStructure.TIM_OutputNState = TIM_OutputNState_Disable;//TIM_OutputNState_Enable;
    TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
    TIM_OCInitStructure.TIM_OCNPolarity = TIM_OCPolarity_Low;
    TIM_OCInitStructure.TIM_OCIdleState = TIM_OCIdleState_Set;
    TIM_OCInitStructure.TIM_OCNIdleState = TIM_OCIdleState_Reset;
   
    TIM_OCInitStructure.TIM_Pulse = 32768;
    TIM_OC1Init(TIM17, &TIM_OCInitStructure);
   
    TIM_Cmd(TIM17, ENABLE);
    TIM_CtrlPWMOutputs(TIM17, ENABLE);
    TIM17->SR=0;

    DMA_InitTypeDef     DMA_InitStructure;
    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1 , ENABLE);
    DMA_DeInit(DMA1_Channel1);    /* DMA1 Channel1 Config */
    DMA_InitStructure.DMA_PeripheralBaseAddr =(uint32_t)TIM17_DMAR_ADDRESS;//(uint32_t)(&(TIM17->CCR1));
    DMA_InitStructure.DMA_PeripheralBaseAddr =(uint32_t)(&(TIM17->CCR1));
    DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)Encode_Tab;
    DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;//DMA_DIR_PeripheralSRC;
    DMA_InitStructure.DMA_BufferSize = 2;
    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_Circular;//DMA_Mode_Normal;//
    DMA_InitStructure.DMA_Priority = DMA_Priority_High;
    DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
    DMA_Init(DMA1_Channel1, &DMA_InitStructure);
     //DMA_ITConfig(DMA1_Channel1, DMA_IT_TC, ENABLE);                         // 开启发送DMA通道中断   
              
    TIM_DMAConfig(TIM17, TIM_DMABase_CCR1,TIM_DMABurstLength_1Transfer);
  /* TIM1 DMA Update enable */
    TIM_DMACmd(TIM17, TIM_DMA_CC1, ENABLE);

    DMA_Cmd(DMA1_Channel1, ENABLE);/* DMA1 Channel1 enable */
}




使用特权

评论回复
沙发
GZZXB|  楼主 | 2021-6-29 18:38 | 只看该作者
本帖最后由 GZZXB 于 2021-6-29 18:45 编辑

同时不明白为什么波形是反转的。 改为TIM_OCMode_PWM2 才是正确的占空比。

使用特权

评论回复
板凳
香水城| | 2021-7-1 16:35 | 只看该作者
我看你的代码 好像是在使用定时器的dma burst传输,你的配置应该有问题。



另外,你每次只是修改一个通道的CCR值,也未必使用burst模式,使用常规DMA传输方式即可。

关于定时器BURST DMA传输模式,这里有篇**可以参考:

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

使用特权

评论回复
地板
GZZXB|  楼主 | 2021-7-4 10:48 | 只看该作者
本帖最后由 GZZXB 于 2021-7-4 11:51 编辑

感谢 香版的回复.  我的理解是定时器的dma burst传输 外设地址是通过TIM17_DMAR_ADDRESS来间接访问,而我是用的TIM17->CCR1.应该是常规传输吧?    TIM_DMAConfig(TIM17, TIM_DMABase_CCR1,TIM_DMABurstLength_1Transfer); 这一句是不是不管什么传输都得加上呢?  另外我在GPIOA7上做 tim3 pwm输入/tim17 pwm输出切换时,就死机。 这个需要注意什么吗?

编辑补充:TIM_DMAConfig(TIM17, TIM_DMABase_CCR1,TIM_DMABurstLength_1Transfer);    常规模式下加不加应该都可以,加上只是设定而已,只要不将目的地址设为DMAR就不起作用.  楼主位代码加上自动重载函数可以输出波形了,  有两个新的问题是初始化时输出是正常的.  而在代码中切换GPIOA7复用功能时直接跑飞。本代码用途是复用GPIOA7, 切换为PWM输入时扑捉GPIOA7上出现的占空比方波. 切换为PWM输出时在GPIOA7上输出不同占空比的方波。


切换为pwm输入代码

        GPIO_PinAFConfig(GPIOA,GPIO_PinSource7,GPIO_AF_1);    //TIM3_CH2  PWM输入捕捉
        GPIO_InitStructure.GPIO_Pin  = GPIO_Pin_7;            
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
        GPIO_InitStructure.GPIO_OType=GPIO_OType_PP;
        GPIO_InitStructure.GPIO_PuPd=GPIO_PuPd_NOPULL;
        GPIO_Init(GPIOA, &GPIO_InitStructure);
        TIM_Cmd(TIM17, DISABLE);                                           //停止PWM输出
        TIM_Cmd(TIM3, ENABLE);                                              //使能PWM输入捕捉
        


切换为输出代码
        #if(1)
        GPIO_PinAFConfig(GPIOA,GPIO_PinSource7,GPIO_AF_5);   //TIM17_CH1 PWM输出
        GPIO_InitStructure.GPIO_Pin  = GPIO_Pin_7;         
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
        GPIO_InitStructure.GPIO_OType=GPIO_OType_PP;
        GPIO_InitStructure.GPIO_PuPd=GPIO_PuPd_NOPULL;
        GPIO_Init(GPIOA, &GPIO_InitStructure);
     #endif
        //TIM_DMACmd(TIM17, TIM_DMA_CC1, ENABLE);
        //DMA_Cmd(DMA1_Channel1,ENABLE);                          //通过dma1 逐次修改占空比
        TIM_Cmd(TIM3, DISABLE);                                           //停止PWM输入


切换为输出后,用该函数发送不同占空比脉冲

void Encode(uint16_t *p,uint8_t dataLen)
{
    uint8_t i;
    for(i=0;i<dataLen;i++)
    {
         Encode_Tab=p;
    }
    DMA_Cmd(DMA1_Channel1, DISABLE);/* DMA1 Channel1 disable */
    DMA1_Channel1->CNDTR=dataLen;
    DMA_Cmd(DMA1_Channel1, ENABLE);/* DMA1 Channel1 enable */
    TIM_Cmd(TIM17, ENABLE);

}
经排查没有指针越界和非法内存访问情况,只要将 Encode_Tab全部填入0不会死机,正常输出波形。 将 Encode_Tab某个单元填入0xff就跑飞,单步运行时发现运行到TIM_Cmd(TIM17, ENABLE);时正常, 一执行TIM_Cmd(TIM17, ENABLE);就跑飞直接死机。

使用特权

评论回复
5
香水城| | 2021-7-6 17:04 | 只看该作者
你说Encode_Tab全部填入0不会死机,正常输出波形。 将 Encode_Tab某个单元填入0xff就跑飞
===》全0的话,输出要么全高要么全低,如何输出波形呢?
===》还有,如果你**使用burst模式,那你的burst长度是多少,每次访问的是哪几个寄存器?

使用特权

评论回复
6
GZZXB|  楼主 | 2021-7-20 19:49 | 只看该作者
香水城 发表于 2021-7-6 17:04
你说Encode_Tab全部填入0不会死机,正常输出波形。 将 Encode_Tab某个单元填入0xff就跑飞
===》全0的话,输 ...

    本来一帧数据是高低电平交替的,全0的话就是看到一帧时间内都是低了。 我还是没有理解为什么你还说我用burst模式,我上面DMA访问寄存器是用TIM17->CCR1了,应该是常规传输吧?  

使用特权

评论回复
7
cyclefly| | 2021-7-23 11:01 | 只看该作者
学习这种解决问题的过程

使用特权

评论回复
8
香水城| | 2021-7-23 12:53 | 只看该作者
嗯,你将 Encode_Tab全部填入0 的话,输出按理一定是固定的电平,恒高或恒低,具体取决于你的PWM模式。

至于 我怀疑你 启用了burst传输模式,是因为看见你DMA配置中用到 DMAR寄存器。
TIM1 and TIM8 DMA address for full transfer (TIMx_DMAR)

后面你说 直接使用CCR作为源或目的 那是常规的DMA配置。就像下面这样:
   DMA_InitStructure.DMA_Channel = DMA_Channel_6;  
  DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)(TIM1_CCR3_ADDRESS) ;
  DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)aSRC_Buffer;
  DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral;

当然,即使使用了_DMAR寄存器,也可以设计成Burst长度为1的DMA传输,一般没这么用。

你说将 Encode_Tab改成非0值时,程序出现跑飞,除了软件配置方面原因外,会不会你硬件上有问题呢。

我看你是基于标准库开发的,F4的标准库有相关例程可以参考:
\STM32F4xx_DSP_StdPeriph_Lib_V1.6.0\Project\STM32F4xx_StdPeriph_Examples\TIM\TIM_DMA

使用特权

评论回复
9
henryyt3| | 2022-7-29 17:47 | 只看该作者
GZZXB 发表于 2021-7-20 19:49
本来一帧数据是高低电平交替的,全0的话就是看到一帧时间内都是低了。 我还是没有理解为什么你还说我 ...

您好,我是学生,刚开始学嵌入式编程,用的也是stm32f030,用库函数写pwm的时候也遇到这样的问题,请问这是什么原因造成的,应该怎么做才能正常输出pwm

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

96

主题

331

帖子

10

粉丝