DMA 示例

功能:采用DMA进行USART的发送,程序运行时,LED1亮灭交替,表示程序正在运行。

当按下KEY0时,产生一个下降沿触发中断,在中断函数中实现DMA的数据传输到USART1上。

//key.h

#ifndef __KEY_H__
#define __KEY_H__
#include "stm32f10x.h"

void Key_Configuration(void);
void EXTI4_IRQHandler(void); //中断

#endif

//key.c

#include "key.h"
#include "MyTime.h"
#include "bitband.h"
#include "dma.h"

void Key_Configuration(void)
{
	GPIO_InitTypeDef GPIO_InitStruct;
	EXTI_InitTypeDef EXTI_InitStruct;
	NVIC_InitTypeDef NVIC_InitStruct;

	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOE | RCC_APB2Periph_AFIO,ENABLE);

	//GPIO_DeInit(GPIOE); //此处绝对不能使用GPIO_DeInit进行默认初始化,因为GPIOE在前的其他地方已经对其某些引脚进行初始化了,这里若使用默认初始化,则会清除之前进行的配置。切记切忌
	GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IPU ; //上拉输入
	GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_InitStruct.GPIO_Pin = GPIO_Pin_4;
	GPIO_Init(GPIOE,&GPIO_InitStruct);
	GPIO_SetBits(GPIOE,GPIO_Pin_4);

	GPIO_EXTILineConfig(GPIO_PortSourceGPIOE,GPIO_PinSource4);//将中断线4与GPIO引脚联系起来

	EXTI_DeInit(); //第一次配置中断,可用默认配置,若之前有配置过EXTI,这里最好不要在用默认配置
	EXTI_InitStruct.EXTI_Line = EXTI_Line4;
	EXTI_InitStruct.EXTI_Mode = EXTI_Mode_Interrupt ;
	EXTI_InitStruct.EXTI_Trigger = EXTI_Trigger_Falling ;
	EXTI_InitStruct.EXTI_LineCmd = ENABLE;
	EXTI_Init(&EXTI_InitStruct);

	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //中断分组
	NVIC_InitStruct.NVIC_IRQChannel = EXTI4_IRQn;
	NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 0;
	NVIC_InitStruct.NVIC_IRQChannelSubPriority = 0;
	NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
	NVIC_Init(&NVIC_InitStruct);

}

extern u32 DMA1_MEM_LEN; //传输数据长度
void EXTI4_IRQHandler(void)
{
	MyDelay_ms(10);
	if(EXTI_GetITStatus(EXTI_Line4) == SET)
	{
		LED0 = !LED0;
		USART_DMACmd(USART1,USART_DMAReq_Tx,ENABLE);   //使能串口1的DMA发送
		DMA_Start(DMA1_Channel4,DMA1_MEM_LEN);	       //开始一次DMA传输
		while(DMA_GetFlagStatus(DMA1_FLAG_TC4) == RESET); //传输未结束		 

		DMA_ClearFlag(DMA1_FLAG_TC4); 
		EXTI_ClearITPendingBit(EXTI_Line4);
	}

}

//dma.h

#ifndef __DMA_H__
#define __DMA_H__

#include "stm32f10x.h"

void DMA_Configuration(u32 DMA_PeripheralBaseAddr,u32 DMA_MemoryBaseAddr,u32 DMA_BufferSize);
void DMA_Start(DMA_Channel_TypeDef*DMA_CHx,u32 DMA1_MEM_LEN);

#endif

//dma.c

#include "dma.h"

void DMA_Configuration(u32 DMA_PeripheralBaseAddr,u32 DMA_MemoryBaseAddr,u32 DMA_BufferSize)
{
	DMA_InitTypeDef DMA_InitStruct;

	RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1 ,ENABLE);

	DMA_DeInit(DMA1_Channel4);
	DMA_InitStruct.DMA_PeripheralBaseAddr = DMA_PeripheralBaseAddr;
	DMA_InitStruct.DMA_MemoryBaseAddr = DMA_MemoryBaseAddr;
	DMA_InitStruct.DMA_DIR = DMA_DIR_PeripheralDST ;
	DMA_InitStruct.DMA_BufferSize = DMA_BufferSize;
	DMA_InitStruct.DMA_PeripheralInc = DMA_PeripheralInc_Disable ;
	DMA_InitStruct.DMA_MemoryInc = DMA_MemoryInc_Enable;
	DMA_InitStruct.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
	DMA_InitStruct.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte ;
	DMA_InitStruct.DMA_Mode = DMA_Mode_Normal ;
	DMA_InitStruct.DMA_Priority = DMA_Priority_Medium ;
	DMA_InitStruct.DMA_M2M = DMA_M2M_Disable ;
	DMA_Init(DMA1_Channel4,&DMA_InitStruct);

}

void DMA_Start(DMA_Channel_TypeDef*DMA_CHx,u32 DMA1_MEM_LEN)
{
	DMA_Cmd(DMA_CHx,DISABLE);//关闭 USART1 TX DMA1所指示的通道
	DMA_SetCurrDataCounter(DMA1_Channel4,DMA1_MEM_LEN);//DMA通道的DMA缓存大小
	DMA_Cmd(DMA_CHx,ENABLE);//开启 USART1 TX DMA1所指示的通道

}

//main.c

#include "bitband.h"
#include "MyTime.h"
#include "key.h"
#include "gpio.h"
#include "dma.h"
#include "usart.h"

u32 DMA1_MEM_LEN = 0;

int main(void)
{
	const unsigned char buf[]={"dma with usart demo!!\r\n"};
	DMA1_MEM_LEN = sizeof(buf)/sizeof(buf[0]);
	MySysTick_Init();
	GPIO_Configuration();
	Key_Configuration();
	USART_Configuration();
	DMA_Configuration((u32)&USART1->DR,(u32)buf,DMA1_MEM_LEN);

	while(1)
	{
		LED1 = !LED1;
		MyDelay_ms(1000);
	}
}

这样,当按下KEY0时,LED0就会翻转之前的状态,串口也能接受到字符串。

时间: 2024-10-10 22:24:49

DMA 示例的相关文章

S3C2440 DMA 驱动示例

将 DMA 抽象为一个字符设备,在初始化函数中调用 void *dma_alloc_writecombine(struct device *dev, size_t size, dma_addr_t *handle, gfp_t gfp) 函数来分配两段物理地址连续的空间,一段作为源空间,一段作为目的空间. 然后将物理地址进行 ioremap 供驱动使用,最后调用 register_chrdev 来注册这个字符设备. DMA 的 regs: #define DMA0_BASE_ADDR 0x4B0

stm32 DMA数据搬运 [操作寄存器+库函数](转)

源:stm32 DMA数据搬运 [操作寄存器+库函数] DMA(Direct Memory Access)常译为“存储器直接存取”.早在Intel的8086平台上就有了DMA应用了. 一个完整的微控制器通常由CPU.存储器和外设等组件构成.这些组件一般在结构和功能上都是独立的,而各个组件的协调和交互就由CPU完成.如此一来,CPU作为整个芯片的核心,其处理的工作量是很大的.如果CPU先从A外设拿到一个数据送给B外设使用,同时C外设又需要D外设提供一个数据...这样的数据搬运工作将使CPU的负荷显

SylixOS DMA子系统之一

1. DMA子系统简介 1.1      DMA简介. DMA的英文拼写是"DirectMemory Access",是一种数据不经过CPU处理,直接由DMA控制器从一块物理内存搬运到另一块物理内存的数据交换模式.在DMA模式下,CPU只须向DMA控制器下达指令,让DMA控制器来处理数据的传送,数据传送完毕再把信息反馈给CPU,这样就很大程度上减轻了CPU资源占有率,可以大大节省系统资源. 2. DMA设备驱动模型 2.1      DMA驱动模型简介 SylixOS中的DMA架构位于

Linux 下的DMA浅析

DMA是一种无需CPU的参与就可以让外设和系统内存之间进行双向数据传输的硬件机制.使用DMA可以使系统CPU从实际的I/O数据传输过程中摆脱出来,从而大大提高系统的吞吐率.DMA经常与硬件体系结构特别是外设的总线技术密切相关. 一.DMA控制器硬件结构 DMA允许外围设备和主内存之间直接传输 I/O 数据, DMA 依赖于系统.每一种体系结构DMA传输不同,编程接口也不同. 数据传输可以以两种方式触发:一种软件请求数据,另一种由硬件异步传输. a -- 软件请求数据 调用的步骤可以概括如下(以r

Zynq PS DMA控制器应用笔记

Zynq PS DMA应用笔记 Hello,Panda Zynq-7000系列器件PS端的DMA控制器采用ARM的IP核DMA-330(PL-330)实现.有关DMA控制器的硬件细节及相关指令集.编程实例内容参考ARM官方文档: DDI0424D:dma330_r1p2_trm.pdf DAI0239A:dma330_example_programs.pdf 本文开发环境为Xilinx SDK2015.2,DMA库版本为dmaps_v2_1. 1 结构特点 DMA控制器具有以下的特点: n   

linux 简单的DMA例程

一个简单的使用DMA 例子 示例:下面是一个简单的使用DMA进行传输的驱动程序,它是一个假想的设备,只列出DMA相关的部分来说明驱动程序中如何使用DMA的. 函数dad_transfer是设置DMA对内存buffer的传输操作函数,它使用流式映射将buffer的虚拟地址转换到物理地址,设置好DMA控制器,然后开始传输数据. int dad_transfer(struct dad_dev *dev, int write, void *buffer,                 size_t c

Dynamic DMA mapping Guide

一.前言 这是一篇指导驱动工程师如何使用DMA API的文档,为了方便理解,文档中给出了伪代码的例程.另外一篇文档dma-api.txt给出了相关API的简明描述,有兴趣也可以看看那一篇,这两份文档在DMA API的描述方面是一致的. 二.从CPU角度看到的地址和从DMA控制器看到的地址有什么不同? 在DMA API中涉及好几个地址的概念(物理地址.虚拟地址和总线地址),正确的理解这些地址是非常重要的. 内核通常使用的地址是虚拟地址.我们调用kmalloc().vmalloc()或者类似的接口返

利用ZYNQ SOC快速打开算法验证通路(3)——PS端DMA缓存数据到PS端DDR

上篇该系列博文中讲述W5500接收到上位机传输的数据,此后需要将数据缓存起来.当数据量较大或者其他数据带宽较高的情况下,片上缓存(OCM)已无法满足需求,这时需要将大量数据保存在外挂的DDR SDRAM中. 最简单的方式是使用Xilinx的读写地址库函数Xil_In32()和Xil_Out32(),当然不仅支持32bit位宽,还包括8 16和64bit.但这种方式每次读写都要占用CPU,无法在读写的同时接收后续数据或者对之前的数据进一步处理,也就无法形成类似FPGA逻辑设计中的"流水线结构&qu

DMA的学习——数据通路的问题?

解决: dma应该只有一个硬件设备(固定映射),然后一个dma顺序完成不同的写任务. bram ctrl的映射地址是edit addr的那个,但是不能直接使,要用宏定义的那个数(后面多了一个U,我也不知道为啥).找自己的bram ctrl的base宏定义是什么名字要去xparameters.h找,看名字找,好像没有表格... 路径:bsp的include里面 重要!记得类型转换成(int *)!!!!!!!!!!!!!!!!!!!!!! static int * Src = (int*)XPAR