用DMA直接驱动GPIO,实现GPIO最高输出速率(转)
先上图:STM32F303芯片,72M的主频
可以看到GPIO的达到了14.4M的翻转速率,
再来上代码:
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOC, ENABLE);
GPIOC->MODER |= 0x55555555;
GPIOC->OSPEEDR |= 0xFFFFFFF;
GPIOC->PUPDR |= 0x55555555;
u32 Gpio_data[]= {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 = ;
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()
{
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[]= {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 = ;
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 = ;
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;
用DMA直接驱动GPIO,实现GPIO最高输出速率(转)的更多相关文章
- linux通用GPIO驱动,写GPIO文件不立即生效问题解决
Linux开发平台实现了通用GPIO的驱动,用户通过,SHell或者系统调用能控制GPIO的输出和读取其输入值.其属性文件均在/sys/class/gpio/目录下,该目录下有export和unexp ...
- linux SPI驱动——简单的gpio模拟SPI驱动测试 (二)
1: /* 2: * Add by xuyonghong for duotin car radio fm 3: * Copyright (C) 2016-5-24 xuyonghong@duotin. ...
- 基于设备树的TQ2440 DMA学习(3)—— DMA控制器驱动
作者 彭东林pengdonglin137@163.com 平台 TQ2440Linux-4.9 概述 上一篇直接操作DMA控制器实现了一个mem2mem的DMA传输,但是这样不符合linux driv ...
- [gpio]Linux GPIO简单使用方式1-sysfs
转自:http://blog.csdn.net/drivermonkey/article/details/20132241 1.1.References 1.2.GPIO Usage from a L ...
- 树莓派 Learning 003 --- GPIO 000 --- GPIO引脚图
树莓派 Learning 003 - GPIO 000 - GPIO引脚图 我的树莓派型号:Raspberry Pi 2 Model B V1.1 装机系统:NOOBS v1.9.2 Raspberr ...
- 迅为4412开发板Linux驱动教程之GPIO的初始化
视频下载地址:http://pan.baidu.com/s/1c06oiti GPIO的初始化 • 在内核源码目录下使用命令“ls drivers/gpio/*.o”,可以看到“gpio-exynos ...
- NUC972当检测到sd卡时,在sd卡驱动中操作gpio开启sd卡的电源,解决sd卡因低电压有时识别不正常的问题
1.根据硬件原理图,找到对应控制sd卡电源的gpio引脚,并在sd卡驱动文件中定义操作改该引脚的宏 2.在sd卡检测函数中,使用glib增加开sd卡电源的操作,如此当sd卡每次被检测到时,驱动中就会自 ...
- stm32开发笔记(三):stm32系列的GPIO基本功能之输出驱动LED灯、输入按键KEY以及Demo
前言 stm32系列是最常用的单片机之一,不同的版本对应除了引脚.外设.频率.容量等'不同之外,其开发的方法是一样的. 本章讲解使用GPIO引脚功能驱动LED灯和接收Key按钮输入. STM ...
- [gpio]Linux GPIO简单使用方式2-sysfs
转自:http://blog.csdn.net/cjyusha/article/details/50418862 在Linux嵌入式设备开发中,对GPIO的操作是最常用的,在一般的情况下,一般都有对应 ...
随机推荐
- poj 3020 Antenna Placement (最小路径覆盖)
二分图题目 当时看到网上有人的博客写着最小边覆盖,也有人写最小路径覆盖,我就有点方了,斌哥(kuangbin)的博客上只给了代码,没有解释,但是现在我还是明白了,这是个最小路径覆盖(因为我现在还不知道 ...
- Amoeba for MySQL
Amoeba for MySQL Amoeba for MySQL致力于MySQL的分布式数据库前端代理层,它主要在应用层访问MySQL的时候充当query 路由功能,专注 分布式数据库 proxy ...
- Django -- static
和templates一样,Django会自动去各个app根目录中寻找叫static的目录,在该目录下创建一个和app同名的目录,用于存放静态文件(js, css. images...) 使用时,只需要 ...
- ab测试 uwsgi遇到的问题
1 请求并发数目较大时,接收到的数目小于发送的数目 1.1 描述:uwsgi正常返回302跳转 ab -n 5000 -c 250 -g test.log "192.168.50.20:90 ...
- 网络层 IP 协议首部格式与其配套使用的四个协议(ARP,RARP,ICMP,IGMP)
目录 IP协议首部格式地址解析协议 ARP逆向地址解析协议 RARP网际控制报文协议 ICMP网际组管理协议IGMP IP 数据报首部 IP数据报首部格式: 最高位在左边,记为0 bit:最低位在右边 ...
- ural1067 Disk Tree
Disk Tree Time limit: 2.0 secondMemory limit: 64 MB Hacker Bill has accidentally lost all the inform ...
- CentOS 在同一窗口打开文件夹
1.打开一个文件夹 2.编辑 - 首选项 - 行为,勾选“总是在浏览器窗口打开”,点击关闭.
- 关于js的几道经典题(作用域、原型链等)自己做的
1. function test() { var a = 1; setTimeout(function() { alert(a); a = 3; }, 1000); a = 2; setTimeout ...
- [Big Data]从Hadoop到Spark的架构实践
摘要:本文则主要介绍TalkingData在大数据平台建设过程中,逐渐引入Spark,并且以Hadoop YARN和Spark为基础来构建移动大数据平台的过程. 当下,Spark已经在国内得到了广泛的 ...
- Android 4.0 ICS SystemUI浅析——StatusBar结构分析
Android 4.0 ICS SystemUI浅析——StatusBar结构分析 分类: Android2012-06-30 14:45 23687人阅读 评论(8) 收藏 举报 androidsi ...