关于嵌入式开发中的SPI驱动

 
关于嵌入式开发中的SPI驱动
 

关于嵌入式开发中的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 */*/,...),

有数据来了产生的中断,因为中断肯定是用来通知接收数据的。

你可能感兴趣的:(关于嵌入式开发中的SPI驱动)