1.为何使用DMA:为了提高CPU的工作效率,避免多余的等待时间
![](https://img-blog.csdn.net/20141226123354317?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbHpqc3Fu/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)
![](https://img-blog.csdn.net/20141226123552659?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbHpqc3Fu/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)
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仍然有效,那么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;
}