首先介绍s3c2410与DMA相关的寄存器。
s3c2410共有4通道的dma,每通道9个寄存器,共36个。
1、DISRCn 该寄存器保存待传送数据的源地址。
2、DISRCCn 源控制寄存器。位1表示数据源的总线类型,位0表示地址是否自动增减。
3、DIDSTn 该寄存器保存待传送数据的目的地址。
4、DIDSTCn 目的控制寄存器。位1表示目的地址的总线类型,位0表示地址是否自动增减。
5、DCON DMA控制寄存器。
6、DSTATn DMA状态寄存器。
7、DCSRCn 当前源地址寄存器。
8、DCDSTn 当前目的地址寄存器。
9、DMASKTRIGn DMA MASK寄存器。
下面是linux-2.6.24.4中和dma有关的函数的分析:
首先定义了几个变量:
static int dma_channels ;//被设定为4
static struct s3c24xx_dma_selection dma_sel ;
struct s3c2410_dma_chan s3c2410_chans [S3C2410_DMA_CHANNELS];
static struct s3c24xx_dma_order * dma_order ;
有关的结构体定义如下:
struct s3c24xx_dma_selection {
struct s3c24xx_dma_map * map ;
unsigned long map_size;
unsigned long dcon_mask;
void ( * select ) ( struct s3c2410_dma_chan * chan,
struct s3c24xx_dma_map * map ) ;
} ;
struct s3c24xx_dma_map {
const char * name;
struct s3c24xx_dma_addr hw_addr;
unsigned long channels[ S3C2410_DMA_CHANNELS] ;
} ;
struct s3c2410_dma_chan {
/* channel state flags and information * /
unsigned char number; /* number of this dma channel * /
unsigned char in_use; /* channel allocated * /
unsigned char irq_claimed; /* irq claimed for channel * /
unsigned char irq_enabled; /* irq enabled for channel * /
unsigned char xfer_unit; /* size of an transfer * /
/* channel state * /
enum s3c2410_dma_state state;
enum s3c2410_dma_loadst load_state;
struct s3c2410_dma_client * client;
/* channel configuration * /
enum s3c2410_dmasrc source;
unsigned long dev_addr;
unsigned long load_timeout;
unsigned int flags; /* channel flags * /
struct s3c24xx_dma_map * map; /* channel hw maps * /
/* channel
struct s3c24xx_dma_order {
struct s3c24xx_dma_order_ch channels[ DMACH_MAX] ;
} ;
struct s3c24xx_dma_order_ch {
unsigned int list [ S3C2410_DMA_CHANNELS] ; /* list of channels */
unsigned int flags; /* flags */
} ;
然后分析各个函数。
int s3c2410_dma_request( unsigned int channel,
struct s3c2410_dma_client * client,
void * dev)
{
struct s3c2410_dma_chan * chan;
unsigned long flags;
int err;
pr_debug( "dma%d: s3c2410_request_dma: client=%s, dev=%p/n" ,
channel, client- > name, dev) ;
local_irq_save( flags) ;
chan = s3c2410_dma_map_channel( channel) ; //获得dma通道
if ( chan = = NULL ) {
local_irq_restore( flags) ;
return - EBUSY;
}
dbg_showchan( chan) ;
chan- > client = client;
chan- > in_use = 1; //占用该dma通道
if ( ! chan- > irq_claimed) {
pr_debug( "dma%d: %s : requesting irq %d/n" ,
channel, __FUNCTION__ , chan- > irq) ;
chan- > irq_claimed = 1;
local_irq_restore( flags) ;
err = request_irq( chan- > irq, s3c2410_dma_irq, IRQF_DISABLED, //申请中断
client- > name, ( void * ) chan) ;
local_irq_save( flags) ;
if ( err) { //中断申请失败
chan- > in_use = 0; //释放申请的通道和其他资源
chan- > irq_claimed = 0;
local_irq_restore( flags) ;
printk( KERN_ERR "%s: cannot get IRQ %d for DMA %d/n" ,
client- > name, chan- > irq, chan- > number) ;
return err;
}
chan- > irq_enabled = 1; //使能中断
}
local_irq_restore( flags) ;
/* need to setup */
pr_debug( "%s: channel initialised, %p/n" , __FUNCTION__ , chan) ;
return 0;
}
可见,该函数向内核申请了资源,即dma通道,然后就可以对申请的通道进行设置了。下面继续。
int s3c2410_dma_config( dmach_t channel, //通道号,和申请时使用的通道号要一致
int xferunit, //发送时位的设置,可以是1、2、或者4,分别对应8、16和32位方式
int dcon) //特别重要,就是dcon寄存器的值
{
struct s3c2410_dma_chan * chan = lookup_dma_channel( channel) ; //得到申请的dma通道
pr_debug( "%s: chan=%d, xfer_unit=%d, dcon=%08x/n" ,
__FUNCTION__ , channel, xferunit, dcon) ;
if ( chan = = NULL )
return - EINVAL;
pr_debug( "%s: Initial dcon is %08x/n" , __FUNCTION__ , dcon) ;
dcon | = chan- > dcon & dma_sel. dcon_mask; //这步的作用是清除dcon寄存器中除了24~26的其他位,从datasheet中知道这三位
//决定dma的中断源
pr_debug( "%s: New dcon is %08x/n" , __FUNCTION__ , dcon) ;
switch ( xferunit) { //设置字节传送的方式
case 1:
dcon | = S3C2410_DCON_BYTE;
break ;
case 2:
dcon | = S3C2410_DCON_HALFWORD;
break ;
case 4:
dcon | = S3C2410_DCON_WORD;
break ;
default :
pr_debug( "%s: bad transfer size %d/n" , __FUNCTION__ , xferunit) ;
return - EINVAL;
}
dcon | = S3C2410_DCON_HWTRIG; //使24~26位的选择有效
dcon | = S3C2410_DCON_INTREQ; //使传送完成的时候产生中断
pr_debug( "%s: dcon now %08x/n" , __FUNCTION__ , dcon) ;
chan- > dcon = dcon;
chan- > xfer_unit = xferunit;
return 0;
}
由以上分析可以知道,该函数完成的主要功能就是设置对应通道的dcon寄存器。关于更细节的东西,可以查看datasheet。
int s3c2410_dma_devconfig( int channel,
enum s3c2410_dmasrc source, //dma传送源的类型,可以是S3C2410_DMASRC_HW和S3C2410_DMASRC_MEM
int hwcfg,
unsigned long devaddr) //传送的目的地址
{
struct s3c2410_dma_chan * chan = lookup_dma_channel( channel) ;
if ( chan = = NULL )
return - EINVAL;
pr_debug( "%s: source=%d, hwcfg=%08x, devaddr=%08lx/n" ,
__FUNCTION__ , ( int ) source, hwcfg, devaddr) ;
chan- > source = source;
chan- > dev_addr = devaddr;
switch ( source) {
case S3C2410_DMASRC_HW: //dma传送源是外围硬件
/* source is hardware */
pr_debug( "%s: hw source, devaddr=%08lx, hwcfg=%d/n" ,
__FUNCTION__ , devaddr, hwcfg) ;
dma_wrreg( chan, S3C2410_DMA_DISRCC, hwcfg & 3) ; //设置源控制寄存器
dma_wrreg( chan, S3C2410_DMA_DISRC, devaddr) ; //设置传送源的地址
dma_wrreg( chan, S3C2410_DMA_DIDSTC, ( 0< < 1) | ( 0< < 0) ) ; //目的地址一般是内存
chan- > addr_reg = dma_regaddr( chan, S3C2410_DMA_DIDST) ; //得到传送目的地址寄存器的地址
return 0;
case S3C2410_DMASRC_MEM: //dma传送源是内存
/* source is memory */
pr_debug( "%s: mem source, devaddr=%08lx, hwcfg=%d/n" ,
__FUNCTION__ , devaddr, hwcfg) ;
dma_wrreg( chan, S3C2410_DMA_DISRCC, ( 0< < 1) | ( 0< < 0) ) ; //传送源控制器
dma_wrreg( chan, S3C2410_DMA_DIDST, devaddr) ; //传送的目的地址
dma_wrreg( chan, S3C2410_DMA_DIDSTC, hwcfg & 3) ; //目的地址控制器
chan- > addr_reg = dma_regaddr( chan, S3C2410_DMA_DISRC) ; //得到传送源地址寄存器的地址
return 0;
}
printk( KERN_ERR "dma%d: invalid source type (%d)/n" , channel, source) ;
return - EINVAL;
}
整个系统中dma的建立过程如下:
首先调用了s3c2410_dma_init(),该函数只有一句:
return s3c24xx_dma_init(4, IRQ_DMA0, 0x40);
其中第一个参数就是通道号,第二个参数为dma的中断号的基数,第三个参数表示各个通道占用的空间的大小。
在函数s3c24xx_dma_init中,主要做了以下几件事情:
1、调用ioremap,将dma控制器的地址做一个映射。
2、为dma分配内核空间。
3、将上面提到的s3c2410_chans数组的内容全部清零。
4、初始化4个s3c2410_dma_chan结构的变量,对其中的一部分成员赋值。
成功结束时,该函数返回0。
第二步,系统调用s3c24xx_dma_order_set函数,如下:
s3c24xx_dma_order_set(&s3c2410_dma_order);
s3c2410_dma_order定义于arch/arm/mach-s3c2410/dma.c文件中,是一个s3c24xx_dma_order类型的结构体。
该函数主要为该结构体分配空间,然后将s3c2410_dma_order的内容copy到dma_order中。
第三步,系统调用s3c24xx_dma_init_map,完成dma通道的映射:
return s3c24xx_dma_init_map(&s3c2410_dma_sel);
下面重点分析一下该函数。
传给该函数的参数定义如下:
static struct s3c24xx_dma_selection __initdata s3c2410_dma_sel = {
. select = s3c2410_dma_select,
. dcon_mask = 7 < < 24,
. map = s3c2410_dma_mappings,
. map_size = ARRAY_SIZE( s3c2410_dma_mappings) ,
} ;
该函数首先为各个通道分配内存空间,分配的总的大小为sizeof(struct s3c24xx_dma_map ) * s3c2410_dma_sel.map_size。
然后,函数把s3c2410_dma_sel的所有内容全部赋给上面提到的dma_sel结构体,该结构体就包含了所有的dma可以申请的通道。
用户申请dma通道的时候,内核就可以在dma_sel的map表中查找,并决定是否可以使用该dma通道。
上一篇:s3c2410_i2c总线驱动及at24c02设备驱动实例
下一篇:linux 2.6.24.4在S3C2410上的移植(CS8900网卡驱动)(基于GEC2410)
推荐阅读最新更新时间:2024-11-10 11:54
推荐帖子
- 【颁奖礼】摸黑抢楼赢大礼!
- 示波器应该算我们身边最铁的哥们了,在实验室里,在工作台上,他们总是与我们形影不离。也许,你已经练就了一身只对示波器的独门秘籍......【颁奖礼】摸黑抢楼赢大礼!
- soso 活动列表
- 华大单片机FLASH操作说明及注意事项
- 华大单片机根据型号不同,涵盖了16/32/64/128/256/512K字节(Byte)容量的FLASH存储器,每块FLASH按照Sector进行划分,每个Sector容量为512字节。本存储器支持对擦除(片/页擦除)、编程以及读取操作。此外,本模块还支持对FLASH存储器擦写的保护,以及控制寄存器的写保护。擦写时间FLASH存储器对擦除和编程操作的控制信号具有严格的时间要求,控制信号的时序不合格会造成擦除操作和编程操作失败或者数据写入深度不够。上电时默认装载了HC
- 火辣西米秀 国产芯片交流
- 【KW41Z】晒板子
- 终于收到板子了【KW41Z】晒板子
- dvd1478 NXP MCU
- 光电转换技术新突破:用红外线与紫外线发电
- 日本的科学家研发出一种新的PV芯片技术,他们在传统的P型GaN薄膜上增添一层钴,并将之制成N型的材料(图右),而该芯片吸收层约为10x10mm,周围长方型的是电极。图左是无钴的P型GaN薄膜。此新技术不但能吸收可见光,包含红外线与紫外线都能转换为电能,将有望生产无多重接点的高性能光电产品。(图/Physorg)光电转换技术新突破:用红外线与紫外线发电
- 天天谈芯 嵌入式系统
- 电子类使用小程序收集
- 本帖最后由paulhyde于2014-9-1503:04编辑想用的时候参考一下啊电子类使用小程序收集本帖最后由paulhyde于2014-9-1503:04编辑都什么东西啊本帖最后由paulhyde于2014-9-1503:04编辑谢谢哟,学习了。本帖最后由paulhyde于2014-9-1503:04编辑都有些什么东西哦8.29本帖最后由paulhyde于2014-9-1503:05
- 非雪之悠 电子竞赛
- EDN新开通“模拟学堂”,提供大量电子电路图下载和在线查看。欢迎访问!
- http://www.ednchina.com/Analog.aspxEDN新开通“模拟学堂”,提供大量电子电路图下载和在线查看。欢迎访问!
- babyjiejie 电源技术
设计资源 培训 开发板 精华推荐
- LTC3589HUJ-1 集成电源 IC 的典型应用电路,用于具有 USB/汽车电池充电器的移动微处理器系统
- NSV50350ADT4G 恒流 LED 灯串驱动器的典型应用
- R_71_V10基于IPS2电机换向传感器的设计
- SRK1000B反激式自适应同步整流控制器
- MAXREFDES1154:基于MAX11410的可配置、四通道、RTD/TC测量系统
- AR0130CSSC00SPCAH-GEVB:1.2 MP Sunex DSL945D 1/3" iLCC CIS HB
- Fl7734 单级初级侧调节 PWM 控制器的典型应用,用于 Pfc 和切相可调光 LED 驱动
- 具有基本抑制功能的 LF50ABDT-TR 5V 极低压降稳压器的典型应用
- 简易电源短路保护电路
- EVAL-AD7666CBZ,用于 AD7666、16 位、500 Ksps PulSAR 模数转换器的评估板