原创 2410 spi 与 DSP vc33 serial 的通讯

2010-3-19 09:54 2934 8 8 分类: 处理器与DSP

转自:http://blog.csdn.net/stargui/archive/2008/05/08/2418367.aspx


2410 spi 与 DSP vc33 serial 的通讯:


因为需要2410 和 vc33通讯, 通讯速率要求 vc33->2410 大于1Mbyte/s , 2410->vc33速率要求较低, 所以主要解决vc33->2410的问题, vc33的串口波特率可以达到30Mbps,  2410的spi口可以达到25Mbps, 因此考虑用2410的spi和vc33的串口来交换数据。


过程如下:2410的spi设置为slave, vc33的串口发送作master。


接线如下:   2410             vc33


               spinss1  <-->  FSX


               spiclk1  <-->  CLKX


               spimiso1 <-->  DX


数据通讯模式考虑到通讯速率,不可能采用polling 或 interrupt模式,只能采用dma模式:


vc33方面的配置:


串口配置:


rSERIOX  = 0x333;


rSERIOR  = 0x111;


 rSERTCON = 0x1EF;


rSERTCNT = 0x0002;


 rSERTCMP = 0x0002;


 rSERCON  = 0xEBD0344;


中断配置: 


asm(" LDI 0121H, IE");


传送:  rDMACON = 0x0000;       // reset DMA


rDMASRC = (unsigned int)src; //  src of data 


rDMADST = 0x808048;    //  serial dx  


rDMACNT = cnt;     //  dma count 


rDMACON = 0x0E13;    //  配置并发送


rSERTXD = 0x55555555;        //  触发发送


 2410 spi dma的linux驱动编写:  


因为以前只针对atmel 的 9260、 9261的dma写过驱动,2410下面的费了一番功夫。


 2410的dma的实现代码在


linux-2.6.24.3/arch/arm/plat-s3c24xx/dma.c 


linux-2.6.24.3/include/asm/arch/dma.h 


看了一下代码:   DMA对硬件进行了抽象, 维护一个等待队列, 队列中保存着每个DMA的请求, 通过几个简单的接口来管理  DMA通道申请、DMA中断申请、控制寄存器设置、挂入DMA等待队列、清除DMA中断、释放DMA通道。  下面详解整个DMA过程: 


 串口配置:  __raw_writeb(0x51, spi_base + 0x00); 


__raw_writeb(0x02, spi_base + 0x08);


 __raw_writeb(0x01, spi_base + 0x0C); 


s3c2410_gpio_cfgpin(S3C2410_GPG5, S3C2410_GPG5_SPIMISO1);


 s3c2410_gpio_cfgpin(S3C2410_GPG7, S3C2410_GPG7_SPICLK1);


 s3c2410_gpio_cfgpin(S3C2410_GPG3, (3<<6)); 


 分配DMA缓冲: 


dmabuffer=dma_alloc_coherent(NULL, SPI_DMA_BUF_SIZE, &dmaphys, GFP_KERNEL|GFP_DMA);


配置DMA:  ret = s3c2410_dma_request(DMACH_SPI1, &s3c2410spi1_dma_in, NULL);


 /*


函数原型:


 int s3c2410_dma_request(unsigned int channel, struct s3c2410_dma_client *client, void *dev); 


功能: 申请DMA资源, 申请DMA中断。 


输入参数:  channel 通道号(这里的通道号在dma.h中声明)     


 client  名称,同样在dma.h中声明。     


 dev     可以是NULL


 */  


s3c2410_dma_setflags(DMACH_SPI1, S3C2410_DMAF_AUTOSTART); 


/*


函数原型:


 int s3c2410_dma_setflags(dmach_t channel, unsigned int flags); 


功能: 设置DMA的标志。 


输入参数:  channel 通道号(这里的通道号在dma.h中声明)   


flag     标志,这里设置为S3C2410_DMAF_AUTOSTART 


*/  


s3c2410_dma_devconfig(DMACH_SPI1, S3C2410_DMASRC_HW, 0x03, 0x59000034); 


/*


函数原型:


int s3c2410_dma_devconfig(int channel,enum s3c2410_dmasrc source, int hwcfg,


                                              unsigned long devaddr)     


功能: 配置DMA的源/目的硬件类型和地址:   


输入参数:  channel   通道号(这里的通道号在dma.h中声明)


source:    S3C2410_DMASRC_HW: src is hardware, S3C2410_DMASRC_MEM: src is memory


hwcfg:     the value for xxxSTCn register,                       


bit 0: 0=increment pointer, 1=leave pointer   bit 1: 0=source is AHB, 1=source is APB


devaddr:   源物理地址 


*/ 


s3c2410_dma_config(DMACH_SPI1, 1, 0xa2800000);


/*


函数原型: 


int s3c2410_dma_config(dmach_t channel, int xferunit, int dcon); 


 功能: 设置配置DMA寄存器。


输入参数:  channel   通道号(这里的通道号在dma.h中声明)        


xfersize:     size of unit in bytes (1,2,4)                 


dcon:         base value of the DCONx register  */  


s3c2410_dma_set_buffdone_fn(DMACH_SPI1, spi_dmain_done_callback); 


/*函数原型: 


int s3c2410_dma_set_buffdone_fn(dmach_t channel, s3c2410_dma_cbfn_t rtn); 


功能: 设置配置DMA寄存器。 


输入参数:  channel   通道号(这里的通道号在dma.h中声明)     


rtn        回调函数, 在DMA完成时调用。 


*/


通过以上过程,DMA通道已经申请并准备好,现面就可以开始DMA的传送了,需要下面的函数:


s3c2410_dma_enqueue(DMACH_SPI1, (void *)dmabuf, dmaphys, SPI_DMA_BUF_SIZE); 


/*


函数原型: 


int s3c2410_dma_enqueue(unsigned int channel, void *id, dma_addr_t data, int size);  


功能: 分配并初始化一个DMA内核缓冲区控制结构, 并将它插入DMA等待队列, 设置DMA控制寄存器内容, 等待DMA操作触发。 


输入参数:  channel   通道号(这里的通道号在dma.h中声明)             


id         the device driver's id information for this buffer                 


data       the physical address of the buffer data                 


size       the size of the buffer in bytes  If the channel is not running, then the flag S3C2410_DMAF_AUTOSTART  is checked, and if set, the channel is started. If this flag isn't set,  then an error will be returned.   It is possible to queue more than one DMA buffer onto a channel at  once, and the code will deal with the re-loading of the next buffer  when necessary. 


*/   


DMA通道把以上请求放入等待队列,在合适的时候会开始请求传送。 


用以下函数可以释放申请的DMA通道: 


int s3c2410_dma_free(dmach_t channel, struct s3c2410_dma_client *client);  


回调函数:  因为回调函数在DMA中断中调用, 中断服务程序在执行时,会屏蔽其它中断。因此,中断服务程序应该执行得越快越好,以免延误其他中断,  而丢失信息。 因此此处用了Tasklet, 以便及时响应其他设备中断。实现如下: 


static void
Serial_OK_Tasklet(unsigned long data)  ...{
//add code do what you want
...   ...   ...  


s3c2410_dma_enqueue(DMACH_SPI1, (void *)dmabuf, dmaphys, SPI_DMA_BUF_SIZE); 


//DMA通道申请下一次传送


首先通过DECLARE_TASKLET(name, func, data)来创建tasklet。


这是一个宏定义:  DECLARE_TASKLET(SerialOKTasklet, Serial_OK_Tasklet, (unsigned long)(0)); 


static void
spi_dmain_done_callback(struct s3c2410_dma_chan *ch, void *buf, int size, enum s3c2410_dma_buffresult result)  ...{


tasklet_schedule(&SerialOKTasklet);   //该tasklet就会在适当的时机得到执行。



通过以上操作,实现了spi的DMA数据交换。  


在调试过程中,一开始DMA怎么也没有进行传送,费了很大事,后来仔细看了DMA.C的代码,发现了几处可疑的地方,


static struct
s3c2410_dma_chan *lookup_dma_channel(unsigned int channel) {


 if (channel & DMACH_LOW_LEVEL)   


return &s3c2410_chans[channel & ~DMACH_LOW_LEVEL];  


else    return dma_chan_map[channel]; 


}



 函数实现查找对应的DMA通道,其中s3c2410_chans对应的是4个物理通道  dma_chan_map[channel]对应的是映射的通道,但是在以后的DMA.C的调用中,出现了传入的是物理通道, 但是却没有DMACH_LOW_LEVEL标志位的错误,主要是这个函数  s3c2410_dma_ctrl(chan->number, S3C2410_DMAOP_START);  改正后  s3c2410_dma_ctrl(chan->number | DMACH_LOW_LEVEL, S3C2410_DMAOP_START);  通讯正常,不知道是不是DMA的BUG。( 转载请著明出处)。                  


发表于 @ 2008年05月08日 19:15:00



本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/stargui/archive/2008/05/08/2418367.aspx

PARTNER CONTENT

文章评论0条评论)

登录后参与讨论
EE直播间
更多
我要评论
0
8
关闭 站长推荐上一条 /3 下一条