你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

查看: 6457|回复: 13

用DMA直接驱动GPIO,实现GPIO最高输出速率

[复制链接]

11

主题

9

回帖

0

蝴蝶豆

高级会员

最后登录
2020-7-28
发表于 2015-2-5 23:24:36 | 显示全部楼层 |阅读模式
本帖最后由 蓝凌风 于 2015-2-5 23:25 编辑

先上图:STM32F303芯片,72M的主频

可以看到GPIO的达到了14.4M的翻转速率,
      再来上代码:
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOC, ENABLE);
GPIOC->MODER |= 0x55555555;
GPIOC->OSPEEDR |= 0xFFFFFFF;
GPIOC->PUPDR |= 0x55555555;
u32 Gpio_data[4]= {0x0000FFFF,0xFFFF0000,0x0000FFFF,0xFFFF0000};
DMA_InitTypeDef          DMA_InitStructure;
TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
NVIC_InitTypeDef NVIC_InitStructure;
/* TIMx clock enable */
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE);
/* DMAx clock enable */
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
DMA_DeInit(DMA1_Channel7);
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)(&(GPIOC->BSRR));         
DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)Gpio_data;
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;  
DMA_InitStructure.DMA_BufferSize = 4;
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Word;
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Word;
DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
DMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh;
DMA_InitStructure.DMA_M2M = DMA_M2M_Enable;         
DMA_Init(DMA1_Channel7, &DMA_InitStructure);
DMA1_Channel7->CCR |= DMA_CCR_EN;
         用DMA内存到内存的模式,直接把Gpio_data的数据循环的搬到GPIOC的BSRR寄存器上来控制GPIOC上电平的翻转,这样使得GPIO的速度达到了最快,输出70ns的脉宽,这已经是达到了DMA总线带宽的极限,要想再提高速度的话,就得提高STM32芯片的主频。
      再来看用代码来实现的话,GPIO能达到多快的速度。
    先是用库函数来操作,在Main函数的While循环来翻转电平
while(1)
{
   GPIO_Write(GPIOC,0xffff);
GPIO_Write(GPIOC,0x0000);
}

可以看到最快只能输出320ns的脉宽电平,而且高低电平脉宽还不一样,那是因为处理while(1)占用了CPU的时间导致的。
      再来看用寄存器直接操作GPIO
while(1)
{
    GPIOC->ODR = 0xFFFF;
GPIOC->ODR = 0x0000;
}

可以看到,最小脉宽电平可以达到40ns,直接操作寄存器的速度明显要比库函数操作要快好多,低电平的时间要比高电平的时间长很多,同样也是因为处理while的原因。
      用CPU操作寄存器可以达到最快的电平翻转,但是这样CPU的资源全用在这上面,不能再做其它的操作。如果用DMA的话,完全可以不占用CPU资源来达到更高速率的GPIO翻转速度。假如我们要根据自己的需求来产生我们所需要的时序,那要怎样做。其实也很简单,我们只要用定时器触发DMA搬一次数据到BSRR寄存器,然后再通过调整Gpio_data数组里的数据,就可以来实现我们所要的时序。
下面的代码就是通过这种方式来实现让GPIOC产生1us脉宽的时钟,
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOC, ENABLE);
GPIOC->MODER |= 0x55555555;
GPIOC->OSPEEDR |= 0xFFFFFFF;
GPIOC->PUPDR |= 0x55555555;
   u32 Gpio_data[4]= {0x0000FFFF,0xFFFF0000,0x0000FFFF,0xFFFF0000};
    DMA_InitTypeDef          DMA_InitStructure;
    TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
    NVIC_InitTypeDef NVIC_InitStructure;
    /* TIMx clock enable */
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE);
    /* DMAx clock enable */
    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
    DMA_DeInit(DMA1_Channel7);
    DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)(&(GPIOC->BSRR));         
    DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)Gpio_data;
    DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;  
    DMA_InitStructure.DMA_BufferSize = 4;
    DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
    DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
    DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Word;
    DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Word;
    DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
    DMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh;
    DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;         
    DMA_Init(DMA1_Channel7, &DMA_InitStructure);
  
    TIM_TimeBaseStructure.TIM_Period = 72;         
    TIM_TimeBaseStructure.TIM_Prescaler = 0x0;      
    TIM_TimeBaseStructure.TIM_ClockDivision = 0x0;   
    TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;   
    TIM_TimeBaseInit(TIM4, &TIM_TimeBaseStructure);
  
    TIM_DMACmd(TIM4, TIM_DMA_Update, ENABLE);
    TIM_SelectOutputTrigger(TIM4,TIM_TRGOSource_Update);
    TIM_Cmd(TIM4, ENABLE);
   DMA1_Channel7->CCR |= DMA_CCR_EN;
<
回复

使用道具 举报

0

主题

6

回帖

0

蝴蝶豆

初级会员

最后登录
2018-11-27
发表于 2015-2-6 08:07:07 | 显示全部楼层
这个思路不错哎
回复 支持 反对

使用道具 举报

19

主题

935

回帖

27

蝴蝶豆

论坛元老

最后登录
2019-7-29
发表于 2015-2-6 08:40:57 | 显示全部楼层
留着以后用到看看
回复 支持 反对

使用道具 举报

9

主题

392

回帖

2

蝴蝶豆

金牌会员

最后登录
2016-11-24
发表于 2015-2-6 09:34:11 | 显示全部楼层
不错不错
回复 支持 反对

使用道具 举报

2

主题

54

回帖

0

蝴蝶豆

中级会员

最后登录
1970-1-1
发表于 2015-2-6 09:35:05 | 显示全部楼层
呵呵  DMA 本来就可以这么干
回复 支持 反对

使用道具 举报

107

主题

812

回帖

5

蝴蝶豆

论坛元老

最后登录
2019-8-28
发表于 2015-2-6 09:35:35 | 显示全部楼层
好贴,赞一个
回复 支持 反对

使用道具 举报

76

主题

5715

回帖

4

蝴蝶豆

论坛元老

最后登录
2020-10-15
发表于 2015-2-6 09:46:10 | 显示全部楼层
DMA,确实不错,有想法。
回复 支持 反对

使用道具 举报

29

主题

290

回帖

15

蝴蝶豆

论坛元老

最后登录
2020-12-3
发表于 2015-2-6 12:45:33 | 显示全部楼层
DMA不错!
回复 支持 反对

使用道具 举报

4

主题

233

回帖

0

蝴蝶豆

高级会员

最后登录
2019-1-10
发表于 2015-7-3 17:43:53 | 显示全部楼层
GOOD IDEA!
回复 支持 反对

使用道具 举报

1

主题

9

回帖

0

蝴蝶豆

初级会员

最后登录
2018-1-9
发表于 2017-10-28 13:36:00 | 显示全部楼层
做个标记
回复 支持 反对

使用道具 举报

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版