关于嵌入式开发中的SPI驱动
SPI的驱动一般要比IIC的简单很多,因为没有复杂的时序。 S3C2410的SPI总线支持主从模式,支持轮询、中断(#define IRQ_SPI0 22 /* SPI interrupt */)和DMA三种方式(SMOD): Polling, Interrupt, and DMA transfer mode 其中采用polling模式的SPI传输的代码尤其简单。例如HHARM9-EDU通过SPI接MCP2510跟ADS7846都是polling模式,下面就是一个典型的通过SPI从AD芯片读取数据的例子: (其实其中的时序是AD芯片的要求,SPI收、发数据就是一句话(SPRDAT0/SPTDAT0寄存器的读写)而已,非常的简单,要比IIC简单得多)。 spi_tx_data(0xD0); x_upper = rSPRDAT0;//dummy data spi_tx_data(0x00); x_upper = rSPRDAT0; spi_tx_data(0x90); x_lower = rSPRDAT0; spi_tx_data(0x00); y_upper = rSPRDAT0; spi_tx_data(0x00); y_lower = rSPRDAT0;
如果是使用DMA方式的SPI传输,代码也很简单,以接收数据read为例: spi_rd /*set SPCON0 to configure properly the SPI module, DMA mode ,SCK enable, master mode , active high , format A, Tx auto garbage data mode */ rSPCON0 = 0x5a;
/*DMA is configured properly*/ /*1.Base address of source data to transfer*/ rDISRC1 = 0x59000014;
/*2.LOC=1:the source is in the peripheral bus*/ /*INC=0:the address is increased by its data size*/ rDISRCC1 = 0x00000002;
/*3.Base address of destination for the transfer, to SDRAM*/ rDIDST1 = dbuf;
/*4.LOC=0:the source is in the system bus*/ /*INC=0:the address is increased by its data size*/ rDISTC1 = 0x00000000;
/*5.DMD_HS=1:Handshake mode is selected;*/ /*SYNC=1:DREQ and DACK are synchronized to HCLK*/ /*INT=1:interrupt request is generated when all the transfer is done*/ /*TSZ=0:a unit transfer is performed*/ /*SERVMODE=0:Single service mode*/ /*HWSRCSEL=011:SPI request DMA;SWHW_SEL=1:select the DMA source from hardware*/ /*RELOAD=1;DSZ=00:Byte to be transferred;TC=length */ rDCON1 = DCON1_DMD_HS|DCON1_SYNC|DCON1_INT|DCON1_TSZ| DCON1_SERVMODE|DCON1_HWSRCSEL|DCON1_SWHW_SEL|RELOAD| DCON1_DSZ|length;
/*6.STOP=1;ON_OFF=1;SW_TRIG=0 start/enable DMA*/ rDMASKTRIG1 = 0x006;
若采用SPI的中断时,这你的驱动代码就要稍微复杂一些了,因为引入中断方式就意味着优化驱动的通信性能的可能性,例如用tasklet方式在中断处理函数中释放CPU,或者用interruptible_sleep_on/wake_up_interruptible来实现阻塞方式的接收。
做IIC/SPI这些总线的驱动时,你必须清楚 1、这些总线的驱动其实就只要提供两个函数即可,即收(read)和发(write) 2、要分清哪些是IIC/SPI通信的时序要求,哪些是所接的器件的时序要求,例如IIC接的X1227/24LC04/UDA1380/IP175等。 SPI其实没有任何时序,非常简单,如果用POLLING方式,驱动代码不超过100行。例如接CAN总线控制器MCP2510,参见参见教材《ARM9 嵌入式Linux系统构建与应用》的P137页,收发就是对SPRDAT0/SPTDAT0的简单读取和赋值而已;而我们看SPI接ADS7846这个 AD接四线触摸屏的时候,它的驱动就写得比较复杂,但它的复杂性在于结合了触摸屏的实际应用特性在里面,例如它的read读取坐标就不能像CAN那样死等,而必须是如果没有按下等操作就必须返回的noblock方式,这样才不会造成上层GUI+触摸屏应用程序的反应迟钝和死锁,而来了数据也不能在中断 ISR里面完成,而要用tasklet并配合一个timer――digi_sam_callback来尽量让CPU不会停留在内核里面的数据读取上,而实际真正的SPI读取数据还是那个touch_pan_read_dev里面的那几句AD芯片的时序,详细分析参见上面教材的P232~P238. /HHARM9-EDU/experiments/EXP19/driver/2410spi.c 这个驱动里面就是当年尝试用SPI的DMA+中断方式写的SPI驱动,但最后没有仔细调试,他们偷懒就放弃还是用POLLING模式了。 这个代码里面: request_irq(INT_DMA1(/*#define IRQ_DMA1 18 /* DMA channel 1 interrupt */*/,...), 有数据来了产生的中断,因为中断肯定是用来通知接收数据的。 |