SPI message 基础 Part 2

来源:互联网 发布:java服务器端开发框架 编辑:程序博客网 时间:2024/06/05 19:59

SPI message基础

Contents

        .Part 1 - Linux SPI系统概览

        .Part 2 - SPI message基础

        .Part 3 - 异步写

LinuxSPI 通信基础

SPI总线上是通过封装一系列的spi_transfer到一个spi_message中,然后将spi_message提交到SPI子系统去。

下面是spi_transfer结构:

struct spi_transfer {    const void*tx_buf;//驱动提供的发送缓冲区dma,    void *rx_buf; //接收缓冲区    unsigned len;    dma_addr_ttx_dma;//发送dma,controller使用    dma_addr_t rx_dma;//接收dma    unsigned cs_change:1;//片选位     u8 bits_per_word;//每字长度    u16 delay_usecs;//延迟    u32 speed_hz; //速度    struct list_headtransfer_list;//transfer 链表};

len is always the # of 8-bitbytes to clock, could be send ,receive or both.

tx_dmarx_dma可通过dma_map_single()来初始化或者让controller来填充这些域。如果你手动的映射这些dma,就必须将spi_message.is_dma_mappped置为1,来告知controller你已经做好映射了。既然手动的做映射也必须手的unmapped掉。并不是所有的transfer都会使用dma,比如,有的控制器在transfer小于8字节时会使用PIO(ProgrammingI/O,cpu执行I/O端口指令进行读写,大数据交换是会提高cpu占有率)模式。

cs_change1会引起CS线在spi_message序列中transfers间变高。通常,CS会在第一个transfer前变低并一直保持直至spi_message序列中最后一个transfer到来(这是本次spi_message中最后一个)。这种反转在和某些设备通信时会非常有用。

bit_per_word对于单个spi_transfer可用来覆盖spi_device.bits_per_word域。清零不做覆盖。

delay_usecs会在spi_message序列中一个transfer之后,CS状态改变前或者下一个transfer修正延迟。

speed_hz允许这个transfer可以有高于spi_device.max_speed_hz的速率。清零不作变化。

transfer_listspi_message序列中用于维护transfer的链表。

spi_transfer中时常更改的域也许只有lentx_bufrx_buf。剩下的当以0来初始化。

单个spi_transfer可表示一次读,一次写或者是一次读写。在SPIcontroller驱动下,所有操作常是全双工的。向spi_transferrx_buf传递一个NULL,这就是一次只写操作,会丢弃MISO线上的数据。同样向tx_buf传递一个NULL,这就是一次只读操作了。spi_transferlen域代表(已经多少字节数据流过总线了)howmany bytes to clock the bus

spi_message结构:

struct spi_message {        struct list_head transfers;        struct spi_device *spi;        unsigned is_dma_mapped:1;        void (*complete)(void*context);        void *context;        unsigned actual_length;        int status;        struct list_head queue;        void *state;};

transfer这个spi_message所包含有的spi_transfer链表头。

is_dma_mappedspi_transfertx_dmarx_dma是否已经mapped

complete回调函数

context提供给complete的可选参数

actual_lengthspi_message已经传输了的字节数

status出错与否,错误时返回errorcode

queue state controller驱动内部使用

在每次使用spi_message可以使用函数:

void spi_message_init(structspi_message *m);

来初始化。

spi_message添加transfers可以使用spi_message_add_tail()函数:

void spi_message_add_tail(structspi_transfer *t, struct spi_message *m);

一旦你准备好了spi_message,就可以使用spi_async()来向SPI系统提交了:

int spi_async(struct spi_device *spi,struct spi_message *message);

因为是异步的,一提交就立马返回了,这也就是说需要同步机制(complete就是了)。他确保不会睡眠,可安全的在中断handler或其他不可休眠的代码中调用。稍后会念念他的好的。

使用spi_async()需要注意的是,在complete()未返回前不要轻易访问你一提交的spi_transfer中的buffer。也不能释放SPI系统正在使用的buffer。一旦你的complete返回了,这些buffer就又是你的了。

使用完成回调机制稍显复杂,可以使用SPI系统提供的另一个同步版本:spi_sync():

int spi_sync(struct spi_device *spi,struct spi_message *message);

因为是同步的,spi_sync提交完spi_message后不会立即返回,会一直等待其被处理。一旦返回就可以重新使用buffer了。spi_sync()drivers/spi/spi.c中实现,其调用了spi_async(),并休眠直至complete返回。

原创粉丝点击