OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
查看: 4986|回复: 41

求助,有关定时器PWM调制和DMA传输的问题

[复制链接]

2

主题

25

帖子

0

精华

初级会员

Rank: 2

积分
51
金钱
51
注册时间
2017-6-18
在线时间
16 小时
发表于 2018-9-10 22:10:37 | 显示全部楼层 |阅读模式
我想要使用TIM定时器产生占空比一直都是50%的脉冲,但是频率会时刻改变,初步的想法是采用内存计算出每个时刻的频率,存入数组,然后通过DMA传输到TIM->ARR 寄存器,但是却无法改变占空比,使用使用DMA传输一次如何同时改变TIM->CCR1 寄存器的值和TIM->ARR 寄存器的值,保证每次改变TIM->ARR 寄存器的值的同时  TIM->CCR1 寄存器值 使用等于  TIM->ARR 寄存器的值的一半??   求大神给我一个思路,很急,多谢了
正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

3

主题

238

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
1366
金钱
1366
注册时间
2016-5-26
在线时间
1698 小时
发表于 2018-9-11 10:18:02 | 显示全部楼层
尤培升 发表于 2018-9-11 10:01
定时器的PWM输出模式有这样的模式吗?只改变TIM->ARR的值就可以控制频率,同时自动控制占空比?

可以用Toggle模式但不解决需要2倍存储的问题。
另外控制频率是不是可以改PSC?
淘汰人的从来是工具而不是年龄
嵌入式的冷知识屋 blog.csdn.net/k_o_carnivist
回复 支持 1 反对 0

使用道具 举报

2

主题

25

帖子

0

精华

初级会员

Rank: 2

积分
51
金钱
51
注册时间
2017-6-18
在线时间
16 小时
 楼主| 发表于 2018-9-10 22:14:36 | 显示全部楼层
使用DMA传输一个参数如何同时改变TIM->ARR和TIM->CCR1 两个寄存器的值,保证占空比始终是50%  ,频率可以随时改变。
回复 支持 反对

使用道具 举报

17

主题

175

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
1016
金钱
1016
注册时间
2014-4-7
在线时间
99 小时
发表于 2018-9-10 22:31:07 | 显示全部楼层
使用比较输出,配好合适的分频,将重置寄存器设置为最大,只需使用DMA改变比较寄存器的值就可以了,改变两次就可以产生一个周期的CLK了,两次的值相同就是占空比为50%的脉冲了
在你没有做出成绩之前,这个世界不会在乎你的自尊。
回复 支持 反对

使用道具 举报

3

主题

1907

帖子

0

精华

论坛元老

Rank: 8Rank: 8

积分
4106
金钱
4106
注册时间
2018-8-14
在线时间
696 小时
发表于 2018-9-10 22:43:03 | 显示全部楼层
DMA Burst适合
回复 支持 反对

使用道具 举报

0

主题

1

帖子

0

精华

新手入门

积分
9
金钱
9
注册时间
2018-9-10
在线时间
2 小时
发表于 2018-9-10 23:46:09 来自手机 | 显示全部楼层
如何发贴
回复 支持 反对

使用道具 举报

2

主题

25

帖子

0

精华

初级会员

Rank: 2

积分
51
金钱
51
注册时间
2017-6-18
在线时间
16 小时
 楼主| 发表于 2018-9-11 08:37:53 | 显示全部楼层
本帖最后由 尤培升 于 2018-9-11 09:45 编辑

我采用S型曲线控制的步进电机,把计算出的S型曲线的  加速阶段和减速阶段  频率值  存储在数组中,两个阶段占用频率点数大约5000以内,一次运动需要占用1万以内个频率点数,占用大约20K以内的字节,如果使用两个参数来输出一个脉冲,一个电机运动的参数就会变成40K,太大了。
我是在 百度文库上看到的这个文章,说的这种控制方式http://xueshu.baidu.com/s?wd=paperuri%3A%28a0bbf5210069df971db447fb57a7885e%29&filter=sc_long_sign&tn=SE_xueshusource_2kduw22v&sc_vurl=http%3A%2F%2Fwenku.baidu.com%2Fview%2F8856d3497f21af45b307e87101f69e314332fa62%3Fpu%3D&ie=utf-8&sc_us=14862290935938190534
回复 支持 反对

使用道具 举报

3

主题

238

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
1366
金钱
1366
注册时间
2016-5-26
在线时间
1698 小时
发表于 2018-9-11 08:51:21 来自手机 | 显示全部楼层
尤培升 发表于 2018-9-11 08:37
我采用S型曲线控制的步进电机,把计算出的S型曲线的  加速阶段和减速阶段  频率值  存储在数组中,两个阶段 ...

单论这个场景的话,你的步进电机驱动器有要求占空比必须50%么?我觉得CCR可能可以不改。
回复 支持 反对

使用道具 举报

2

主题

25

帖子

0

精华

初级会员

Rank: 2

积分
51
金钱
51
注册时间
2017-6-18
在线时间
16 小时
 楼主| 发表于 2018-9-11 09:38:09 | 显示全部楼层
我刚刚看了电机驱动手册,没发现要求占空比的值,我先试试这种方式

drv8880.pdf

1.71 MB, 下载次数: 41

回复 支持 反对

使用道具 举报

2

主题

25

帖子

0

精华

初级会员

Rank: 2

积分
51
金钱
51
注册时间
2017-6-18
在线时间
16 小时
 楼主| 发表于 2018-9-11 10:01:53 | 显示全部楼层
K.O.Carnivist 发表于 2018-9-11 08:51
单论这个场景的话,你的步进电机驱动器有要求占空比必须50%么?我觉得CCR可能可以不改。

定时器的PWM输出模式有这样的模式吗?只改变TIM->ARR的值就可以控制频率,同时自动控制占空比?
回复 支持 反对

使用道具 举报

3

主题

1907

帖子

0

精华

论坛元老

Rank: 8Rank: 8

积分
4106
金钱
4106
注册时间
2018-8-14
在线时间
696 小时
发表于 2018-9-11 10:17:31 | 显示全部楼层
尤培升 发表于 2018-9-11 08:37
我采用S型曲线控制的步进电机,把计算出的S型曲线的  加速阶段和减速阶段  频率值  存储在数组中,两个阶段 ...

你为什么要一次算这么多呢?只算256个, DMA读了128, 你再算128, 这不行么?
回复 支持 反对

使用道具 举报

2

主题

25

帖子

0

精华

初级会员

Rank: 2

积分
51
金钱
51
注册时间
2017-6-18
在线时间
16 小时
 楼主| 发表于 2018-9-11 12:21:38 | 显示全部楼层
本帖最后由 尤培升 于 2018-9-11 22:35 编辑

我是希望把  S型曲线的加速过程 、 匀速过程、减速过程分成三段,分别采用DMA传输,这样只需要存储加速过程和减速过程的数组,匀速过程的频率只是一个参数,就可以存储整个运动过程的频率参数
回复 支持 反对

使用道具 举报

2

主题

25

帖子

0

精华

初级会员

Rank: 2

积分
51
金钱
51
注册时间
2017-6-18
在线时间
16 小时
 楼主| 发表于 2018-9-11 20:29:28 | 显示全部楼层
本帖最后由 尤培升 于 2018-9-11 20:31 编辑

这个资料描述的方式一直没办法实现。使用定时器中断的方式很好理解,但是使用DMA来更新频率数据到定时器来改变PWM频率就很难理解了,主要是不懂如何进行DMA和定时器的配置

一种步进电机运动控制系统设计—基于stm32系列单片机.pdf

1.35 MB, 下载次数: 57

回复 支持 反对

使用道具 举报

3

主题

1907

帖子

0

精华

论坛元老

Rank: 8Rank: 8

积分
4106
金钱
4106
注册时间
2018-8-14
在线时间
696 小时
发表于 2018-9-11 21:31:18 | 显示全部楼层
尤培升 发表于 2018-9-11 20:29
这个资料描述的方式一直没办法实现。使用定时器中断的方式很好理解,但是使用DMA来更新频率数据到定时器来 ...

如果只是变频率, 而占空比是固定50%那应该很容易啊, 为何实现不了?
回复 支持 反对

使用道具 举报

2

主题

25

帖子

0

精华

初级会员

Rank: 2

积分
51
金钱
51
注册时间
2017-6-18
在线时间
16 小时
 楼主| 发表于 2018-9-11 21:47:12 | 显示全部楼层
edmund1234 发表于 2018-9-11 21:31
如果只是变频率, 而占空比是固定50%那应该很容易啊, 为何实现不了?

我不会设置频率参数通过DMA传输的方式到TIM->ARR寄存器,我在编程序的时候发现,DMA传输没办法通过定时器溢出事件来控制,比如说定时器溢出一次,就让DMA从内存更新一个频率参数到TIM->ARR寄存器。而且DMA每次都只能传输一个数据,TIM->ARR寄存器的值在改变,TIM->CCR2寄存器的值就需要改变,如何做到始终保证占空比50%,TIM->CCR2寄存器的值始终是TIM->ARR寄存器的值的一半,关键是不能频繁使用中断来更新寄存器的值,如果一个电机运动过程中频繁使用中断就无法完成多个电机同时运动情况。
回复 支持 反对

使用道具 举报

2

主题

25

帖子

0

精华

初级会员

Rank: 2

积分
51
金钱
51
注册时间
2017-6-18
在线时间
16 小时
 楼主| 发表于 2018-9-11 21:50:21 | 显示全部楼层
void TIM1_DMA_Config(DMA_Channel_TypeDef* DMA_CHx,u32 Memory,u32 cpar,u16 cndtr)
{
        NVIC_InitTypeDef                                         NVIC_InitStructure;
        DMA_InitTypeDef                                         DMA_InitStructure;
        RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);       
       
  DMA_DeInit(DMA_CHx);  
       
               
        NVIC_InitStructure.NVIC_IRQChannel                                                                                 =         DMA1_Channel5_IRQn;          
        NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority         =                1;                                                                                  
        NVIC_InitStructure.NVIC_IRQChannelSubPriority                                 =         1;                                                         
        NVIC_InitStructure.NVIC_IRQChannelCmd                                                                         =         ENABLE;                    
        NVIC_Init(&NVIC_InitStructure);

        DMA1_MEM_LEN=cndtr;
        DMA_InitStructure.DMA_MemoryBaseAddr = Memory;  
        DMA_InitStructure.DMA_PeripheralBaseAddr = cpar;  
        DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;  
        DMA_InitStructure.DMA_BufferSize = cndtr;  
        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_High;
        DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;  
        DMA_Init(DMA_CHx, &DMA_InitStructure);
        DMA_ITConfig(DMA_CHx, DMA_IT_TC, ENABLE);
        DMA_ClearITPendingBit(DMA_IT_HT);
        DMA_ClearITPendingBit(DMA_IT_TC);
}

void MYDMA_Enable(DMA_Channel_TypeDef*DMA_CHx)
{
        DMA_Cmd(DMA_CHx, DISABLE );  
        DMA_SetCurrDataCounter(DMA_CHx,DMA1_MEM_LEN);
        DMA_Cmd(DMA_CHx, ENABLE);  
}          
void TIM1_S(uint16_t ARR,uint16_t CCR)
{
                GPIO_InitTypeDef                                         GPIO_InitStructure;
                TIM_TimeBaseInitTypeDef         TIM_BaseInitStructure;
                TIM_OCInitTypeDef                                  TIM_OCInitStructure;

                GPIO_PinRemapConfig( GPIO_FullRemap_TIM1,        ENABLE);                                                                                         
               
                RCC_APB2PeriphClockCmd(        RCC_APB2Periph_GPIOE | RCC_APB2Periph_AFIO, ENABLE);
                RCC_APB2PeriphClockCmd( RCC_APB2Periph_TIM1,ENABLE);

                GPIO_InitStructure.GPIO_Pin                 =         GPIO_Pin_11;                //PWMÂö3åêä3öê1Äüòy½Å
                GPIO_InitStructure.GPIO_Speed         =         GPIO_Speed_50MHz;                                                          
                GPIO_InitStructure.GPIO_Mode                 =         GPIO_Mode_AF_PP;
                GPIO_Init(GPIOE, &GPIO_InitStructure);

                TIM_DeInit(TIM1);

                TIM_BaseInitStructure.TIM_Period                                                                                         =                ARR;               
                TIM_BaseInitStructure.TIM_Prescaler                                                                         =                5;                        
                TIM_BaseInitStructure.TIM_ClockDivision                                                         =         0;
                TIM_BaseInitStructure.TIM_CounterMode                                                                 =         TIM_CounterMode_Up;
                TIM_BaseInitStructure.TIM_RepetitionCounter                                         =         0;
                TIM_TimeBaseInit(TIM1, &TIM_BaseInitStructure);       

                TIM_OCInitStructure.TIM_OCMode                                                                               =         TIM_OCMode_Inactive;         
                TIM_OCInitStructure.TIM_OutputState                                                                          =         TIM_OutputState_Enable;
                TIM_OCInitStructure.TIM_OutputNState                                                                         =         TIM_OutputNState_Enable;
                TIM_OCInitStructure.TIM_Pulse                                                                                                 =                CCR;                                                                          
                TIM_OCInitStructure.TIM_OCPolarity                                                                           =         TIM_OCPolarity_Low;   
                TIM_OCInitStructure.TIM_OCNPolarity                                                                          =         TIM_OCNPolarity_High;   
                TIM_OCInitStructure.TIM_OCIdleState                                                                          =         TIM_OCIdleState_Reset;   
                TIM_OCInitStructure.TIM_OCNIdleState                                                                         =         TIM_OCIdleState_Reset;   

                TIM_OC2Init(TIM1,&TIM_OCInitStructure);                                                                          
                TIM_OC2PreloadConfig(TIM1, TIM_OCPreload_Enable);
                TIM_OC4PreloadConfig(TIM1, TIM_OCPreload_Disable);

                TIM_SelectSlaveMode(TIM1, TIM_SlaveMode_Trigger);
    TIM_SelectMasterSlaveMode(TIM1,TIM_MasterSlaveMode_Enable);
    TIM_SelectInputTrigger(TIM1,TIM_TS_ITR1);
               
                TIM_ARRPreloadConfig(TIM1, ENABLE);
                TIM_SelectOutputTrigger(TIM1, TIM_TRGOSource_Update);  
                TIM_DMAConfig(TIM1, TIM_DMABase_ARR, TIM_DMABurstLength_2Bytes);
                TIM_DMACmd(TIM1, TIM_DMA_Update, ENABLE);
//                TIM_ClearFlag(TIM1, TIM_FLAG_Update);                                                                                                       
//                TIM_ITConfig(TIM1, TIM_IT_Update, ENABLE);                                                                                   

                TIM_Cmd(TIM1, ENABLE); //DISABLE
}

这是我写的定时器和DMA传输的程序

回复 支持 反对

使用道具 举报

3

主题

1907

帖子

0

精华

论坛元老

Rank: 8Rank: 8

积分
4106
金钱
4106
注册时间
2018-8-14
在线时间
696 小时
发表于 2018-9-11 21:52:32 | 显示全部楼层
尤培升 发表于 2018-9-11 21:47
我不会设置频率参数通过DMA传输的方式到TIM->ARR寄存器,我在编程序的时候发现,DMA传输没办法通过定时器 ...

有一种DMA模式叫做DMA Burst, 别说一更新ARR, CCR1了, 你想的话,从CR1更新到CCR4都可以
回复 支持 反对

使用道具 举报

3

主题

1907

帖子

0

精华

论坛元老

Rank: 8Rank: 8

积分
4106
金钱
4106
注册时间
2018-8-14
在线时间
696 小时
发表于 2018-9-11 21:54:54 | 显示全部楼层
不知道怎样用dma burst 就去看看这帖子http://www.openedv.com/forum.php?mod=viewthread&tid=278717
回复 支持 反对

使用道具 举报

2

主题

25

帖子

0

精华

初级会员

Rank: 2

积分
51
金钱
51
注册时间
2017-6-18
在线时间
16 小时
 楼主| 发表于 2018-9-11 21:57:43 | 显示全部楼层
本帖最后由 尤培升 于 2018-9-11 21:59 编辑
edmund1234 发表于 2018-9-11 21:31
如果只是变频率, 而占空比是固定50%那应该很容易啊, 为何实现不了?

我想实现 一个芯片驱动多个步进电机,并且可以同时运动,运动的同时可以进行加减速,互相之间不能影响,我目前只在网上找到了一个理论就是,计算出S型曲线的频率参数存储在缓存内,通过DMA传输频率参数到定时器 ARR 寄存器来改变频率,实际写程序却发现,DMA的传输不受定时器溢出的控制,DMA传输速度非常快。因此就卡在这里,我在百度文库找的这个文章的理论是否正确?是否能够实现?您能帮我分析一下吗?

一种步进电机运动控制系统设计—基于stm32系列单片机.pdf

1.35 MB, 下载次数: 39

回复 支持 反对

使用道具 举报

3

主题

1907

帖子

0

精华

论坛元老

Rank: 8Rank: 8

积分
4106
金钱
4106
注册时间
2018-8-14
在线时间
696 小时
发表于 2018-9-11 22:06:27 | 显示全部楼层
尤培升 发表于 2018-9-11 21:57
我想实现 一个芯片驱动多个步进电机,并且可以同时运动,运动的同时可以进行加减速,互相之间不能影响, ...

你的意思是128个数据它DMA就2~3us就传完了,  这是错误的, 只有Mem2Mem的时候是这样, 其它对外置的传送是要被触发后才传一个或一组数据的,
TIM的溢出当然是可以触发DMA传送数据, 不能触发那是你没配置好而已


回复 支持 反对

使用道具 举报

2

主题

25

帖子

0

精华

初级会员

Rank: 2

积分
51
金钱
51
注册时间
2017-6-18
在线时间
16 小时
 楼主| 发表于 2018-9-11 22:11:27 | 显示全部楼层
edmund1234 发表于 2018-9-11 22:06
你的意思是128个数据它DMA就2~3us就传完了,  这是错误的, 只有Mem2Mem的时候是这样, 其它对外置的传送 ...

但是DMA库函数里面没有一个函数可以配置DMA传输的触发源的?
1.JPG
回复 支持 反对

使用道具 举报

3

主题

1907

帖子

0

精华

论坛元老

Rank: 8Rank: 8

积分
4106
金钱
4106
注册时间
2018-8-14
在线时间
696 小时
发表于 2018-9-11 22:13:16 | 显示全部楼层
在TIM库, TIM_DMAConfig大慨是这样的
回复 支持 反对

使用道具 举报

3

主题

1907

帖子

0

精华

论坛元老

Rank: 8Rank: 8

积分
4106
金钱
4106
注册时间
2018-8-14
在线时间
696 小时
发表于 2018-9-11 22:16:43 | 显示全部楼层
本帖最后由 edmund1234 于 2018-9-11 22:21 编辑

你有reference manual吗?没的话去官网下一份
要给TIM配置DMA, 先要查DMA通道, 是要固定的通过配固定的TIM, 不是随便一个都可以用的, TIM配那个通道在reference manual里

这是103的

Capture.PNG
回复 支持 反对

使用道具 举报

2

主题

25

帖子

0

精华

初级会员

Rank: 2

积分
51
金钱
51
注册时间
2017-6-18
在线时间
16 小时
 楼主| 发表于 2018-9-11 22:17:59 | 显示全部楼层
本帖最后由 尤培升 于 2018-9-11 22:22 编辑
edmund1234 发表于 2018-9-11 22:13
在TIM库, TIM_DMAConfig大慨是这样的

我都进行设置了,是不是设置错了?我用的是DMA通道5,定时器1,PWM通道2
3.JPG
4.JPG
5.JPG
回复 支持 反对

使用道具 举报

3

主题

1907

帖子

0

精华

论坛元老

Rank: 8Rank: 8

积分
4106
金钱
4106
注册时间
2018-8-14
在线时间
696 小时
发表于 2018-9-11 22:23:40 | 显示全部楼层
尤培升 发表于 2018-9-11 22:17
我都进行设置了,是不是设置错了?我用的是通道5

比如你是用TIM1的溢出的话题, 就找TIM_UP, 即通道5
回复 支持 反对

使用道具 举报

3

主题

1907

帖子

0

精华

论坛元老

Rank: 8Rank: 8

积分
4106
金钱
4106
注册时间
2018-8-14
在线时间
696 小时
发表于 2018-9-11 22:28:47 | 显示全部楼层
尤培升 发表于 2018-9-11 22:17
我都进行设置了,是不是设置错了?我用的是DMA通道5,定时器1,PWM通道2

这个TIM_DMAConfig(。。。。。。。BurstLength_2Byte)错的
先要搞清楚你现在想只更新ARR吗?还是连CCR也更新?
回复 支持 反对

使用道具 举报

2

主题

25

帖子

0

精华

初级会员

Rank: 2

积分
51
金钱
51
注册时间
2017-6-18
在线时间
16 小时
 楼主| 发表于 2018-9-11 22:30:36 | 显示全部楼层
edmund1234 发表于 2018-9-11 22:23
比如你是用TIM1的溢出的话题, 就找TIM_UP, 即通道5

这是我程序,您能帮我看看么?我确实没找到问题点,谢谢了

多轴运动测试程序.zip

8.88 MB, 下载次数: 44

回复 支持 反对

使用道具 举报

3

主题

1907

帖子

0

精华

论坛元老

Rank: 8Rank: 8

积分
4106
金钱
4106
注册时间
2018-8-14
在线时间
696 小时
发表于 2018-9-11 22:32:35 | 显示全部楼层
本帖最后由 edmund1234 于 2018-9-11 22:38 编辑

DMA Burst 对更新寄存器的排序是ARR, RCR, CCR1, CCR2,。。。。。
所以你要更新Arr和CCR1就必须把RCR也更新, 就是用TIM_DMABurstLength_3Transfers, 不是byte

回复 支持 反对

使用道具 举报

2

主题

25

帖子

0

精华

初级会员

Rank: 2

积分
51
金钱
51
注册时间
2017-6-18
在线时间
16 小时
 楼主| 发表于 2018-9-11 22:34:24 | 显示全部楼层
edmund1234 发表于 2018-9-11 22:28
这个TIM_DMAConfig(。。。。。。。BurstLength_2Byte)错的
先要搞清楚你现在想只更新ARR吗?还是连CCR ...

我是想更新ARR的同时把ARR值得一半赋值给CCR
回复 支持 反对

使用道具 举报

2

主题

25

帖子

0

精华

初级会员

Rank: 2

积分
51
金钱
51
注册时间
2017-6-18
在线时间
16 小时
 楼主| 发表于 2018-9-11 22:46:53 | 显示全部楼层
本帖最后由 尤培升 于 2018-9-11 22:49 编辑

如何配置定时器溢出触发DMA传输呢?
7.JPG
回复 支持 反对

使用道具 举报

3

主题

1907

帖子

0

精华

论坛元老

Rank: 8Rank: 8

积分
4106
金钱
4106
注册时间
2018-8-14
在线时间
696 小时
发表于 2018-9-11 22:52:24 | 显示全部楼层
                TIM_DMAConfig(TIM1, TIM_DMABase_ARR, TIM_DMABurstLength_3Transfers);                // ******
                TIM_DMACmd(TIM1, TIM_DMA_Update, ENABLE);
//                TIM_ClearFlag(TIM1, TIM_FLAG_Update);                                                                                                          //ÇåÖжϣ¬ÒÔÃâÒ»ÆôÓÃÖжϺóÁ¢¼´²úÉúÖжÏ
//                TIM_ITConfig(TIM1, TIM_IT_Update, ENABLE);                                                                                   

        //=====================================        DMA1_Channel5
        DMA_InitStructure.DMA_MemoryBaseAddr = 0;                                                                                //        ???
        DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)&TIM1->DMAR;                                        //*******
        DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;                                                          //*******
        DMA_InitStructure.DMA_BufferSize = cndtr;                                                                                  //        ???        
        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_High;                                                         //*******
        DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;                                                                          //*******
        DMA_Init(DMA1_Channel5, &DMA_InitStructure);                                                                          //*******

        DMA_Cmd(DMA1_Channel5,ENABLE);                                                                                                        //*******        
回复 支持 反对

使用道具 举报

3

主题

1907

帖子

0

精华

论坛元老

Rank: 8Rank: 8

积分
4106
金钱
4106
注册时间
2018-8-14
在线时间
696 小时
发表于 2018-9-11 23:03:20 | 显示全部楼层
本帖最后由 edmund1234 于 2018-9-11 23:10 编辑

        然后
        
        u16 buffer[3xn];
        
        Arr                 RCR                CCR1              Arr                  RCR               CCR1               
        buffer[0]         buffer[1]         buffer[2]         buffer[3]         buffer[4]         buffer[5] 。。。。。。。。
        
        buffer[1] & buffser[4] 。。。。。。。。 == 0, 别改动它
        
        只更新buffer[0+n*3](ARR)及 buffer[2+n*3]CCR1


       把DMA_InitStructure.DMA_MemoryBaseAddr = buffer;   

回复 支持 反对

使用道具 举报

3

主题

1907

帖子

0

精华

论坛元老

Rank: 8Rank: 8

积分
4106
金钱
4106
注册时间
2018-8-14
在线时间
696 小时
发表于 2018-9-11 23:05:19 | 显示全部楼层
尤培升 发表于 2018-9-11 22:46
如何配置定时器溢出触发DMA传输呢?

TIM_DMACmd(TIM1, TIM_DMA_Update, ENABLE);这一句不就是了吗?
回复 支持 反对

使用道具 举报

2

主题

25

帖子

0

精华

初级会员

Rank: 2

积分
51
金钱
51
注册时间
2017-6-18
在线时间
16 小时
 楼主| 发表于 2018-9-12 16:58:27 | 显示全部楼层
edmund1234 发表于 2018-9-11 23:05
TIM_DMACmd(TIM1, TIM_DMA_Update, ENABLE);这一句不就是了吗?

void TIM1_DMA_S_Uni(DMA_Channel_TypeDef* DMA_CHx,u32 Memory,u32 cpar,u16 cndtr)
{
        NVIC_InitTypeDef                                         NVIC_InitStructure;
        DMA_InitTypeDef                                         DMA_InitStructure;
        RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);        //ê1ÄüDMA′«êä
       
        DMA_DeInit(DMA_CHx);   
       
       
        NVIC_InitStructure.NVIC_IRQChannel                                                                                 =         DMA1_Channel5_IRQn;          
        NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority         =                1;                                                                                  
        NVIC_InitStructure.NVIC_IRQChannelSubPriority                                 =         1;                                                         
        NVIC_InitStructure.NVIC_IRQChannelCmd                                                                         =         ENABLE;                            
        NVIC_Init(&NVIC_InitStructure);

        DMA1_MEM_LEN=cndtr;
        DMA_InitStructure.DMA_MemoryBaseAddr = Memory;
        DMA_InitStructure.DMA_PeripheralBaseAddr = cpar;
        DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;  
        DMA_InitStructure.DMA_BufferSize = cndtr;  
        DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;  
        DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Disable;  
        DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;  
        DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
        DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;  
        DMA_InitStructure.DMA_Priority = DMA_Priority_High;
        DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;  
        DMA_Init(DMA_CHx, &DMA_InitStructure);  
       
        DMA_ITConfig(DMA_CHx, DMA_IT_TC, ENABLE);
        DMA_ClearITPendingBit(DMA_IT_HT);
        DMA_ClearITPendingBit(DMA_IT_TC);
}
void TIM1_S(uint16_t ARR,uint16_t CCR)
{
                GPIO_InitTypeDef                                         GPIO_InitStructure;
                TIM_TimeBaseInitTypeDef         TIM_BaseInitStructure;
                TIM_OCInitTypeDef                                  TIM_OCInitStructure;

                GPIO_PinRemapConfig( GPIO_FullRemap_TIM1,        ENABLE);                                                                                                  //ÖØDÂó3éätim11ü½Å
               
                RCC_APB2PeriphClockCmd(        RCC_APB2Periph_GPIOE | RCC_APB2Periph_AFIO, ENABLE);
                RCC_APB2PeriphClockCmd( RCC_APB2Periph_TIM1,ENABLE);

                GPIO_InitStructure.GPIO_Pin                 =         GPIO_Pin_11;                //PWMÂö3åêä3öê1Äüòy½Å
                GPIO_InitStructure.GPIO_Speed         =         GPIO_Speed_50MHz;                                                          
                GPIO_InitStructure.GPIO_Mode                 =         GPIO_Mode_AF_PP;
                GPIO_Init(GPIOE, &GPIO_InitStructure);

                TIM_DeInit(TIM1);

                TIM_BaseInitStructure.TIM_Period                                                                                         =                ARR;                //ÖüÆúêy¾Y
                TIM_BaseInitStructure.TIM_Prescaler                                                                         =                100;                         //Ô¤·ÖÆμêyá¿
                TIM_BaseInitStructure.TIM_ClockDivision                                                         =         0;
                TIM_BaseInitStructure.TIM_CounterMode                                                                 =         TIM_CounterMode_Up;
                TIM_BaseInitStructure.TIM_RepetitionCounter                                         =         0;
                TIM_TimeBaseInit(TIM1, &TIM_BaseInitStructure);       

                TIM_OCInitStructure.TIM_OCMode                                                                               =         TIM_OCMode_PWM2;         
                TIM_OCInitStructure.TIM_OutputState                                                                          =         TIM_OutputState_Enable;
                TIM_OCInitStructure.TIM_OutputNState                                                                         =         TIM_OutputNState_Enable;
                TIM_OCInitStructure.TIM_Pulse                                                                                                 =                CCR;                                                                          
                TIM_OCInitStructure.TIM_OCPolarity                                                                           =         TIM_OCPolarity_Low;            
                TIM_OCInitStructure.TIM_OCNPolarity                                                                          =         TIM_OCNPolarity_High;   
                TIM_OCInitStructure.TIM_OCIdleState                                                                          =         TIM_OCIdleState_Reset;   
                TIM_OCInitStructure.TIM_OCNIdleState                                                                         =         TIM_OCIdleState_Reset;  

                TIM_OC2Init(TIM1,&TIM_OCInitStructure);                                                                          
                TIM_OC2PreloadConfig(TIM1, TIM_OCPreload_Enable);
//                TIM_OC4PreloadConfig(TIM1, TIM_OCPreload_Disable);

                TIM_ARRPreloadConfig(TIM1, ENABLE);
               
                TIM_SelectSlaveMode(TIM1, TIM_SlaveMode_Trigger);
    TIM_SelectMasterSlaveMode(TIM1,TIM_MasterSlaveMode_Enable);
//    TIM_SelectInputTrigger(TIM1,TIM_TS_ITR0);
               
               
//                TIM_SelectOutputTrigger(TIM1, TIM_TRGOSource_Update);  //
                TIM_DMAConfig(TIM1, TIM_DMABase_ARR, TIM_DMABurstLength_1Byte);
                TIM_DMACmd(TIM1, TIM_DMA_Update, ENABLE);
//                TIM_ClearFlag(TIM1, TIM_FLAG_Update);                                                                                                       
//                TIM_ITConfig(TIM1, TIM_IT_Update, ENABLE);                                                                                   
       
                TIM_Cmd(TIM1, ENABLE); //DISABLE
                TIM_CtrlPWMOutputs(TIM1,ENABLE);
}

int main()
{


while(1)
     {
                        delay_ms(1000);
                        TIM1_DMA_S_Uni(DMA1_Channel5,(u32)&M1_Uni_Speed,(u32)&TIM1->DMAR,3200);
                        TIM1_S(571,285);
                        DMA_Cmd(DMA1_Channel5, ENABLE);
                       
                        while(Get_DMA_Staus()==false)
                        {
                                delay_ms(100);
                        }
                        TIM_Cmd(TIM1, DISABLE); //DISABLE
                        DMA_Cmd(DMA1_Channel5, DISABLE);
                        Set_DMA_Status(false);
                        delay_ms(1000);
                        delay_ms(1000);
     }
}



我采用了DMA循环发送的方式发送了3200次,最终检测发现脉冲数多发了(3200个脉冲电机转一圈),我不懂,定时器和DMA如何启动,同时启动吗?还是只需要启动定时器就可以自动触发DMA传输?还是只启动DMA传输,寄存器数据更新会自动启动定时器?
在加速阶段结束之后我在中断里面设置了匀速阶段的DMA配置,但是发现电机这时候会出现很短暂的卡顿,如果想要更改DMA配置的内存地址和DMA传输模式,如何能尽量在中断里面缩短代码执行时间,精简代码?   比如说我是不是可以不需要完全重新配置DMA参数就可以更改DMA传输模式为循环传输模式,并且设定传输次数?

回复 支持 反对

使用道具 举报

3

主题

1907

帖子

0

精华

论坛元老

Rank: 8Rank: 8

积分
4106
金钱
4106
注册时间
2018-8-14
在线时间
696 小时
发表于 2018-9-12 17:34:55 | 显示全部楼层
本帖最后由 edmund1234 于 2018-9-12 17:36 编辑

被始化后
DMA_Cmd(DAM1_Channel5, Enable);
TIM_Cmd(TIM1, Enable);
停止后再启动
DMA_Cmd(DAM1_Channel5, Disable);
DAM1_Channel5->CNDTR=BufferSize; //重写
DAM1_Channel5->ISFR=0x0F<<((5-1)*4);
DMA_Cmd(DAM1_Channel5, Enable);

除了初始外设外, 我很少用库的, 你自己查一下库函数是怎样写的吧
回复 支持 反对

使用道具 举报

29

主题

338

帖子

1

精华

金牌会员

Rank: 6Rank: 6

积分
1181
金钱
1181
注册时间
2018-4-13
在线时间
170 小时
发表于 2018-9-13 08:42:10 | 显示全部楼层
我还没有学习DMA和PWM,只是前段时间略略看过。DMA应该可以一次改变多个单元值,只要是连续单元就可以。而ARR和CCRx是连续单元。
回复 支持 反对

使用道具 举报

2

主题

25

帖子

0

精华

初级会员

Rank: 2

积分
51
金钱
51
注册时间
2017-6-18
在线时间
16 小时
 楼主| 发表于 2018-9-15 18:27:40 | 显示全部楼层
本帖最后由 尤培升 于 2018-9-15 18:29 编辑
edmund1234 发表于 2018-9-12 17:34
被始化后
DMA_Cmd(DAM1_Channel5, Enable);
TIM_Cmd(TIM1, Enable);

不好意啊,我试了使用DMA传输参数到定时器来驱动步进电机,发现DMA是各通道不能并行发送数据的,因此DMA1下的各个通道同一时刻只能让一个电机运动,无法做到同时运动,请问你有别的方法能够  多个步进电机同时运动的方法吗?我查了网上很多人在说一个定时插补的概念,一直不懂这个方法跟驱动多个电机联动有关系吗?请问还有别的办法来同时驱动多个电机吗?
1.PNG
回复 支持 反对

使用道具 举报

3

主题

1907

帖子

0

精华

论坛元老

Rank: 8Rank: 8

积分
4106
金钱
4106
注册时间
2018-8-14
在线时间
696 小时
发表于 2018-9-15 21:32:07 | 显示全部楼层
尤培升 发表于 2018-9-15 18:27
不好意啊,我试了使用DMA传输参数到定时器来驱动步进电机,发现DMA是各通道不能并行发送数据的,因此DMA1 ...

一个电机用DMA_Burst只需一个DMA通道, 比如:

        电机                触发                       DMA_Channel       
        1                TIM1_up                5
        2                TIM2_up                2
        3                TIM3_UP                3
        4                TIM4_UP                7
回复 支持 反对

使用道具 举报

2

主题

25

帖子

0

精华

初级会员

Rank: 2

积分
51
金钱
51
注册时间
2017-6-18
在线时间
16 小时
 楼主| 发表于 2018-9-16 12:40:33 | 显示全部楼层
edmund1234 发表于 2018-9-15 21:32
一个电机用DMA_Burst只需一个DMA通道, 比如:

        电机                触发                       DMA_Channel       

但是 ,如果2个电机同时运动,例如需要DMA1下的通道5和通道2同一个时刻同时传输参数到定时器,互相之间不会影响吗?比如通道5和通道2是不能同时响应DMA传输的吧?例如DMA1下的通道5正在传输参数,此时对DMA1下的通道2进行配置,就会出现错误, 是这样的吗?我看手册上写的同一时刻只能响应一个DMA请求,因此DMA1下的各个通道是不能并行传输数据的,是这样吗?请问有别的方法来实现多个电机同步运行不互相影响吗?
2.PNG
回复 支持 反对

使用道具 举报

3

主题

1907

帖子

0

精华

论坛元老

Rank: 8Rank: 8

积分
4106
金钱
4106
注册时间
2018-8-14
在线时间
696 小时
发表于 2018-9-16 13:10:28 | 显示全部楼层
本帖最后由 edmund1234 于 2018-9-16 13:14 编辑
尤培升 发表于 2018-9-16 12:40
但是 ,如果2个电机同时运动,例如需要DMA1下的通道5和通道2同一个时刻同时传输参数到定时器,互相之间不 ...

下划线的文字, 是说同一通道同一时间只可以有一个触发源的意思
这是英文的原意思
The 7 requests from the peripherals (TIMx[1,2,3,4], ADC1, SPI1, SPI/I2S2, I2Cx[1,2] and
USARTx[1,2,3]) are simply logically ORed before entering the DMA1, this means that only
one request must be enabled at a time. Refer to Figure 50.

logically ORed指的是下图红圈的东东

Capture.PNG
回复 支持 反对

使用道具 举报

2

主题

25

帖子

0

精华

初级会员

Rank: 2

积分
51
金钱
51
注册时间
2017-6-18
在线时间
16 小时
 楼主| 发表于 2018-9-16 13:51:55 | 显示全部楼层
edmund1234 发表于 2018-9-16 13:10
下划线的文字, 是说同一通道同一时间只可以有一个触发源的意思
这是英文的原意思
The 7 requests from ...

奥,懂了,也就是说两个定时器同时溢出并请求DMA触发传输参数,只能认为一个请求有效,就意味着DMA1下各通道不能实现并行传输对么?  因为如果可以,应该能够同一时刻响应多个触发信号。
回复 支持 反对

使用道具 举报

3

主题

1907

帖子

0

精华

论坛元老

Rank: 8Rank: 8

积分
4106
金钱
4106
注册时间
2018-8-14
在线时间
696 小时
发表于 2018-9-16 19:42:09 | 显示全部楼层
尤培升 发表于 2018-9-16 13:51
奥,懂了,也就是说两个定时器同时溢出并请求DMA触发传输参数,只能认为一个请求有效,就意味着DMA1下各 ...

是, 不同的通道是可以同一时间工作的
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则



关闭

原子哥极力推荐上一条 /2 下一条

正点原子公众号

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2025-6-20 05:44

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

快速回复 返回顶部 返回列表