2410 spi 与 DSP vc33 serial 的通讯:

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。( 转载请著明出处)。                   

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值