S3C6410 SPI全双工读写流程分析(原创)(二)

2014-11-24 10:42:30 · 作者: · 浏览: 1
Os, CPU (orDMA) must access the registerSPI_RX_DATA and then data are automatically sentto the register SPI_RX_DATA.

所以,对于处在内核空间的驱动来说,发送数据是往SPI_TX_DATA寄存器里写数据,接收是往SPI_RX_DATA寄存器里读数据。当然没这么简单!!

3 SPI发数据流程分析

提醒一点:SPI支持全双工,注意外设是半双工还是全双工?

按照上文设置,我们每次发送和接收一个byte。

(1)置0 NSSOUT

(2)往SPI_TX_DATA寄存器写一个byte,byte数据会自动移入TX FIFO,因为(1)中已经选中了外设,所以SPI master会自动读取TX FIFO中的byte数据移入TX移位寄存器,并开始发往bus。

(3)也就是说,驱动只需要从内核空间往SPI_TX_DATA寄存器上写数据,就完成了SPI发数据的操作了。

(4)全双工,意味着,发数据的同时也要从SPI_RX_DATA寄存器中读一个byte数据。但是,有可能第一次读并不会真正读到数据,因为没有数据被接收到RX移位寄存器。所以忽略这次的读取数据。

(5)置1 NSSOUT

4 SPI接收数据流程分析

如果外设是单双工,考虑在读数据的时候对spi复位!因为如果读数据发生在写数据后面,数据已经在发数据时读取到RX FIFO中了,只需从SPI_RX_DATA中取出数据就行了。

(1)置0 NSSOUT

(2)因为全双工,在发送数据的同时,spi master会读取byte字节并移入RX FIFO。所以从SPI_RX_DATA寄存器读取一个byte,byte数据会自动R从X FIFO移入到SPI_RX_DATA寄存器。(3)也就是说,驱动只需要从内核空间往SPI_RX_DATA寄存器读取数据,就完成了SPI接收数据的操作了。

(4)全双工,意味着,接收数据的同时也要从SPI_TX_DATA寄存器中发送一个byte数据。但是,读数据的时候发送的数据可能不是真正想要发送的数据,因为有些外设不是全双工工作。

(5)置1 NSSOUT

5 SPI收发条件判断

这是SPI收发协议里最难的部分了。

SPI状态寄存器:

\

1 是否准备好发数据?

/*     spi_wait_TX_ready()- wait for TX_READY and TX_DONE       */
static BOOL spi_wait_TX_ready( void)
{
         unsignedlong loops = msecs_to_loops(10);
         u32val = 0;
         do{
                   val= readl(spiregs + S3C_SPI_STATUS);
         }while(!((val & SPI_STUS_TX_DONE) && (val & SPI_STUS_TX_FIFORDY))&& loops--);
        
         if(loops == 0)
                   returnFALSE;
         else
                   returnTRUE;
}


2 发数据是否完成?

/*     spi_wait_TX_done()- wait for TX_DONE         */
static BOOL spi_wait_TX_done( void)
{
         unsignedlong loops = msecs_to_loops(10);
         u32val = 0;
         do{
                   val= readl(spiregs + S3C_SPI_STATUS);
         }while(!(val & SPI_STUS_TX_DONE)  &&loops--);
        
         if(loops == 0)
                   returnFALSE;
         else
                   returnTRUE;
}


3 是否准备好接收数据?

/*     spi_wait_RX_ready()- wait for RX_READY      */
static BOOL spi_wait_RX_ready( void)
{
         unsignedlong loops = msecs_to_loops(10);
         u32val = 0;
         do{
                   val= readl(spiregs + S3C_SPI_STATUS);
         }while(!(val & SPI_STUS_TRAILCNT_ZERO) && loops--);
        
         if(loops == 0)
                   returnFALSE;
         else
                   returnTRUE;
}

6 最终全双工SPI从半双工外设发送和接收数据函数

BOOL spi_sendbyte( BYTE data)
{
         BYTEchr;
         u32spi_chcfg = spiregs + S3C_CH_CFG;
 
         if(!spi_wait_TX_ready())
         {
                   printk(%s:failed to get tx channel.
);
                   returnFALSE;
         }
         writel(data, spiregs + S3C_SPI_TX_DATA);
         while(!spi_wait_RX_ready());
         readl(spiregs + S3C_SPI_RX_DATA);
         returnTRUE;
}
 
/*     spi_flush_fifo()- Clear the TxFIFO , RxFIFO and TX/RX shift register
 *     @spiregs: the SPI register address*/
VOID spi_flush_fifo(void *spiregs)
{
         /*     soft rest the spi controller, flush theFIFO       */
         if(spi_wait_TX_done())
         {
                   writel(readl(spiregs+ S3C_CH_CFG) | SPI_CH_SW_RST, spiregs + S3C_CH_CFG);
                   writel(readl(spiregs+ S3C_CH_CFG) & ~SPI_CH_SW_RST, spiregs + S3C_CH_CFG);
         }
}
 
/*     spi_readbyte()- Read a byte received on SPI0         */
BYTE spi_readbyte( void)
{
         u32tmp;
         u32spi_chcfg = spiregs + S3C_CH_CFG;
         BYTEret;
 
         if(!spi_wait_TX_ready())
                   returnFALSE;
         spi_flush_fifo(spiregs);
         writel(0xFF, spiregs + S3C_SPI_TX_DATA);
        
         if(spi_wait_RX_ready())
         {
                   tmp= readl(spiregs + S3C_SPI_RX_DATA);
                   ret= tmp & 0xff;
         }
         returnret;
}