三十七.DMA---直接存储访问

1.为何使用DMA:为了提高CPU的工作效率,避免多余的等待时间

2.关于DMA控制器:
(1)通道数:2440有4个通道,6410有4个DMA控制器(初始化的时候要选择),32个通道。210有两种DMA一种是内存与内存之间,另外则是普通的内存与外设之间。

(2)请求源:


(3)基本时序

nXDREQ请求生效并经过2CLK周期同步后,nXDACK响应并开始生效,但至少还要经过3CLK的周期延迟,DMA控制器才可获得总线的控制权,并开始数据传输
(4)工作模式:
•Demond模式:
如果DMA完成一次请求后如果Request仍然有效,那么DMA就认为这是下一次DMA请求,并立即开始下一次的传输

•Handshake模式:
DMA完成一次请求后等待Request信号无效,如果Request无效,DMA会无效ACK两个时钟周期,再等待下一次Request。

3.初始化
(1)源地址寄存器初始化(总线模式以及地址是否增加,还有选择通道,指定地址)
(2)目的地址寄存器初始化
(3)控制寄存器初始化(选择DMA请求源,选择源是软件还是硬件,是否重加载以及计数值决定发送多少数据)

4.DMA传输
用置位寄存器的方式打开

5.用到的datashhet
(1)

(2)


(3)


(4)

(5)

(6)




(7)

6.代码实现

7.
(1)期初不能实现,怀疑DMA工作模式设置不对,再次检查代码
(2)发现代码正确,于是怀疑时钟设置,查看时钟,发现正确
(3)怀疑老师的时钟设置错误,应该用AHB的时钟,改了以后还是不行
(4)怀疑启动代码阶段代码,查看以后找不出毛病
(5)怀疑只能用中断方式使用mini2440的DMA,怀疑硬件与tq2440不一样导致,但是用了网上的中断代码,还是不行。
(6)怀疑开发板坏掉,换了开发板还是不行,证明硬件完好,至于软件有关
(7)怀疑串口初始化---------------------------真相大白了,就是串口初始化,之前做串口的时候,使用的轮询或者中断,在这里要配合DMA使用

所以修改串口初始化,将UCON0的【3:2】改为10

8.实现效果终于来了,这么个小错误,花了小君君宝贵的一个下午





9.6410代码
/****************************
@File:dma.c
@
@Tiny6410裸机下学期代码
@DMA设置文件,前提是UART支持DMA模式
@Author:小君君
@****************************/

#include "common.h"

char dam_buf[100] = "\n\rI Love Junjun\n\r成都国嵌是一个很有爱的家庭\n\r"; 

void dma_init()
{
	/*0.使用安全DMA(SDMAC)*/
	(vi DMA_SEL) = 0;
	
	/*1.使能同步逻辑,因为外设UART和SDMAC的时钟不一样*/
	(vi DMACSync) = 0;
	
	/*2.开启DMA控制器*/
	(vi DMACConfiguration) = 1;
	
	/*3.指定源地址寄存器,也就是指定要传送的数据源的首地址*/
	(vi DMACC0SrcAddr) = (unsigned long)dam_buf;
	
	/*4.指定DMA要将数据传送到的地方是UART0通道的发送缓冲寄存器,也就是目的地址寄存器*/
	(vi DMACC0DestAddr) = (unsigned long)UTXH0_DMA;
	
	/*4.设置源主机选择AHB主机1,全局变量是内存中的数据,当然是系统总线上的部件,设置为地址增加模式*/
	/*目标主机选择AHB主机2,因为UART0是在APB总线上,他是一个固定的寄存器所以地址不变化*/
	(vi DMACC0Control0) |= ( (1 << 31) |(0 << 27)|(1 << 26)|(1 << 25)|(0 << 24));	
	
	/*5.设置传输的数据量*/
	(vi DMACC0Control1) = 100;
	
	/*6.允许DMA请求,disables locked transfers ,eminal count interrupt enable ,
	流控制和传输类型:MTP 为 001,目标外设:DMA_UART0_1,源外设:DMA_MEM */
	(vi DMACC0Configuration) |= ((1 << 15) | (1 << 14) |(1 << 11) | (1 << 6));
	
	/*7.将串口配置成DMA发送模式*/
	(vi UCON0)  = 0x9; 
	
}



void dma_start()
{
	/*开启DMA传输*/
	(vi DMACC0Configuration)  = 1;
}


/****************************
@File:common.h
@
@Tiny6410裸机下学期代码
@常用头文件定义
@Author:小君君
@****************************/



#ifndef __COMMON_H__
#define __COMMON_H__

#define  vi   *( volatile unsigned long * ) 

#define ulong unsigned long




/*取消使用mmu*/

//#define MMU_ENABLE 1
/*LED初始化*/

#ifndef MMU_ENABLE
	#define LED_CON 0x7F008800
	#define LED_DAT  0x7F008808
#else
	#define LED_CON 0xA0008800
	#define LED_DAT  0xA0008808
#endif

void mmu_init();

void led_init();
void led_on();
void led_off();
void led1_on();
void led2_on();
void led3_on();
void led4_on();
void led5_on();
void led6_on();
void led7_on();
void led8_on();


/*按键相关初始化*/
#define KEYCON  0x7f008830
#define KEYCON1 0x7f008814

#define K1_MSK (3 << 0)
#define K2_MSK (3 << 2)
#define K3_MSK (3 << 4)
#define K4_MSK (3 << 6)
#define K5_MSK (3 << 8)
#define K6_MSK (3 << 10)
#define K7_MSK (0xF << 12)
#define K8_MSK (0xF << 16)


#define K1_OK (2 << 0)
#define K2_OK (2 << 2)
#define K3_OK (2 << 4)
#define K4_OK (2 << 6)
#define K5_OK (2 << 8)
#define K6_OK (2 << 10)
#define K7_OK (0x3 << 12)
#define K8_OK (0x3 << 16)

void button_init();


/*中断控制器相关的寄存器地址*/
#define EXT_INT_0_CON       0x7f008900   
#define EXT_INT_1_CON       0x7f008904  
#define EXT_INT_0_MASK      0x7f008920 
#define EXT_INT_0_PEND      0x7f008924     

#define VIC0INTENABLE       0x71200010   
#define VIC1INTENABLE       0x71300010

#define EINT0_VECTADDR      0x71200100 /*每个中断源有一个寄存器存放相应的中断处理函数的地址,共32+32 = 64个*/
#define EINT1_VECTADDR      0x71200104
#define EINT2_VECTADDR      0x71200108
#define EINT3_VECTADDR      0x7120010C
#define EINT4_VECTADDR      0x71200110
#define EINT5_VECTADDR      0x71200114/*以上是VIC0,见6410datasheet的P414*/

#define EINT19_VECTADDR     0x71300100     
#define EINT20_VECTADDR     0x71300104 /*以上是VIC1*/


#define VIC0ADDRESS         0x71200f00   
#define VIC1ADDRESS         0x71300f00

void irq_init();


/*nandflash相关寄存器定义*/
#define NFCONF  0x70200000 
#define NFCONT  0x70200004 
#define NFCMMD  0x70200008 
#define NFADDR  0x7020000C 
#define NFDATA  0x70200010 
#define NFDATA8 (*(volatile unsigned char *)0x70200010) 
#define NFSTAT  0x70200028

int nand_erase(unsigned int block_addr);
int Nand_PageWrite(unsigned long start_addr,char *buf);


/*UART相关寄存器定义*/
#define UARTCON     0x7F008000
#define ULCON0      0x7F005000
#define UCON0       0x7F005004
#define UFCON0      0x7F005008
#define UMCON0      0x7F00500C
#define UTRSTAT0    0x7F005010
#define UFSTAT0     0x7F005018

#define UTXH0      (*((volatile unsigned char *)0x7F005020))//注意是char类型的
#define URXH0      (*((volatile unsigned char *)0x7F005024))
#define UBRDIV0    (*((volatile unsigned short *)0x7F005028))//注意是short类型的
#define UDIVSLOT0  (*((volatile unsigned short *)0x7F00502C))

#define UART_FIFO_ENABLE 1  //最好使用FIFO模式,就是必须有这个宏定义

void uart_init();

#ifdef	UART_FIFO_ENABLE
	char getchar(void);
	void putchar(char c);
	void send_string(char* str);
#else
	unsigned char getchar(void);
	void putchar(unsigned char c);
	void send_string(unsigned char* str);
#endif


/*DMA相关定义*/

#define UTXH0_DMA 0x7F005020
#define DMA_BASE 0x75000000

#define DMACC0SrcAddr  (DMA_BASE + 0x100)
#define DMACC0DestAddr (DMA_BASE + 0x104)
#define DMACC0Control0 (DMA_BASE + 0x10C)

#define DMACC0Control1 (DMA_BASE + 0x110)
#define DMACC0Configuration (DMA_BASE + 0x114)
#define DMACC0ConfigurationExp (DMA_BASE + 0x118)

#define DMACC0LLI (DMA_BASE + 0x108)
#define DMACEnbldChns (DMA_BASE + 0x01C)
#define DMACConfiguration (DMA_BASE + 0x030)
#define DMACSync (DMA_BASE + 0x034)
#define DMA_SEL 0x7E00F110

void dma_init();
void dma_start();

#endif


/****************************
@File:main.c
@
@Tiny6410裸机下学期代码
@DMA快车道测试文件
@Author:小君君
@****************************/

#include "common.h"

int main(void)
{
	int num = 1000;
	
	//mmu_init();//MMU初始化,这里不使用MMU
	
	led_init();//LED的GPIO初始化
	
	button_init();//按键初始化
	
	irq_init();//中断初始化
	
	led_on();//点亮4颗LED
	
	uart_init();//串口初始化
	
	putchar('a');
	putchar('\r');
	putchar('\n');
	putchar('b');
	putchar('\r');
	putchar('\n');
	
	
	dma_init();//DMA初始化
	dma_start();//启动DMA发送数据到串口
	
	uart_init();//串口再次初始化,使得串口恢复中断或者轮询模式
	
	while(1){
		printf("=================================================\n\r");
		printf("===================JUN-BOOT======================\n\r");
		printf("0.Send the ARP to get yhe host's MAC address\n\r");
		printf("1.Download the linux kernel from tftp\n\r");
		printf("2.Boot linux OS from SDRAM\n\r");
		printf("3.Junjun is a houmorous\n\r");
		printf("请输入0-3任意一个数字:\n\r");
		
		scanf("%d",&num);	
		
		switch(num){
			case 0:
				printf("请支持成都国嵌\n\r");
				break;
			case 1:
				printf("国嵌学院=====打造你的嵌入式人生\n\r");
				break;
			case 2:
				printf("学ARM,学Linux,学C++,学安卓,学嵌入式,就到成都国嵌学院\n\r");
				break;
			default:
				printf("只要你肯努力,你的明天就会等你!!\n\r");
				break;
			
		}
	}
	return 0;	
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值