1. 硬件原理
计算机系统中各种常用的数据输入/输出方法有查询方式(包括无条件及条件传送方式)和中断方式,这些方式适用于CPU与慢速及中速外设之间的数据交换。但当高速外设要与系统内存或者要在系统内存的不同区域之间进行大量数据的快速传送时,就在一定程度上限制了数据传送的速率。直接存储器存取(DMA)就是为解决这个问题提出的,采用DMA方式,在一定时间段内,由DMA控制器取代CPU,获得总线控制权,来实现内存与外设或者内存的不同区域之间大量数据的快速传送。
SC2440支持位于系统总线与外围总线之间的四通道DMA控制。每一通道的DMA都可以处理一下四种情况:
1.源和目的器件均可以在系统总线
2.源器件在系统总线而目的器件在外围总线
3.源器件在外围总线而目的器件在系统总线
4.源和目的器件均可以在外围总线
DMA最大的有点就是可以在没有CPU干涉的情况下进行数据的传送。可以通过软件控制DMA启动,或者通过内部请求或者外部请求引脚启动。
2. 芯片手册
3. mini2440电路图
4. S3C2440寄存器
DISRCx 源初始化寄存器,存储发送源的地址。
DISRCCx 源初始化控制寄存器,[0]控制地址增长模式,[1]用于配置源是在AHB总线还是在APB总线。
DIDSTx 目标初始化寄存器,存储接收目标的地址。
DIDSTCx 目标初始化控制寄存器,[0]控制地址增长模式,[1]用于配置源是在AHB总线还是在APB总线,[2]选择中断触发的时间。
DCONx DMA控制寄存器,
DSTATx 状态寄存器,只读。
DCSRCx DMA现在的源地址,只读。
DCDSTx DMA现在的目标地址,只读。
DMASKTRIGx DMA屏蔽触发寄存器,开启DMA开关。
dma-uart.c
#include "def.h"
#include "mmu.h"
#include "2440addr.h"
#define GLOBAL_CLK //相当于定义了FCLK,HCLK,PCLK,UCLK
#define PCLK1 50000000
#define UART_CLK PCLK1
#define UART_BAUD_RATE 115200
#define UART_BRD ((int)(UART_CLK/(UART_BAUD_RATE*16)+0.5)-1)
#define TXD0READY (1<<2)
#define RXD0READY (1)
#define SEND_DATA ( *(volatile unsigned char *) 0x30200000)
#define SEND_ADDR (volatile unsigned char *) 0x30200000 //发送源地址
void DMA_Init(void)
{
rUCON0 = rUCON0 & 0xff3 | 0xa;//UART0 dma收发
/****** DMA0 Initialize *****/
rDISRC0 = (U32)(SEND_ADDR);
rDISRCC0 = (0<<1)|(0<<0); //Src=AHB,Increment
rDIDST0 = (U32)UTXH0; // Tx FIFO address
rDIDSTC0 = (1<<1)|(1<<0); //Dst=APB,Fixed;
rDCON0 = (0<<31)|(0<<30)|(1<<29)|(0<<28)|(0 << 27) | (1 << 24) | (1 << 23) | (1 << 22) | (0 << 20) | (50);
//handshake,Sync=APB,IntEn, unit, single, dst=UART0, HwReqMode, NoAutoReload,Halfword,
rDMASKTRIG0 = (1<<1); //DMA0En
}
void Uart0_Init(void)
{
rGPHCON &= ~(0xf<<4)|(0xa<<4); //GPH2,GPH3用作TXD0,RXD0
rGPHUP=0x0c; //GPH2,GPH3内部上拉
rULCON0=0x03; //数据格式:数据位为8位
// rUCON0=0x245; //允许查询或中断方式,不使用DMA通道,并设置接收超时
rUFCON0=0x00; //不使用FIFO
rUMCON0=0x00; //不使用流控
rUBRDIV0=UART_BRD; //设置波特率为115200kb/s
}
void Main(void)
{
volatile unsigned char *p=SEND_ADDR;
int i;
SEND_DATA=0x41;
for(i=0;i<128;i++)
*p++=0x41+i;
MMU_Init();
Uart0_Init();
DMA_Init();
while(1);
}