查看cananl是否启动_SPI 总线协议和驱动

协议介绍

SPI(Serial Peripheral Interface),即串行外设接口,是一种串口通信接口协议。SPI遵循主从模式框架设计架构,但只能有一个主设备。SPI总线有4条信号线,CS(片选信号线),SCLK(时钟信号线),MOSI(主出从入信号线)和MISO(主入从出信号线),因此SPI是全双工总线。SPI的工作原理比较简单,主设备控制片选和时钟输出,输出数据到从设备及读取从设备输入的数据。

SPI协议有四种时钟工作模式(Mode0,Mode1,Mode2和Mode3),要求主从设备工作模式一致。从设备在出厂之后,时钟工作模式已经固定,一般通过修改主设备的时钟工作模式来匹配从设备时钟模式。SPI的四种工作模式取决于时钟极性(CPOL)和时钟相位(CPHA)的组合,时钟极性CPOL用来配置SCLK的电平处于哪种状态时是空闲态或者工作态,而时钟相位CPHA用来配置数据采样在哪个时钟沿:

(1)CPOL=0,表示SCLK低电平时是空闲态,也就是SCLK高电平时是工作态

(2)CPOL=1,表示SCLK高电平时是工作态,也就是SCLK低电平时是工作态

(3)CPHA=0,表示数据采样在第一个时钟沿,数据发送在第二个时钟沿

(4)CPHA=1,表示数据采样在第二个时钟沿,数据发送在第一个时钟沿

协议工作时序图如下(图片来源于网络):

SPI总线具有传输速率快,全双工和硬件电路简单等有点,但是有个缺点:没有类似于I2C总线的应答机制。

内核框架

内核中SPI总线协议框架类似于I2C的总线框架。核心层提供spi_master,spi_device,spi_driver,spi_message和spi_transfer核心数据结构和API接口,供上层系统注册主设备驱动,从设备以及从设备驱动。

1,数据结构:

(1)struct spi_master:主设备和驱动。spi_master结构包含主设备速率,工作模式,统计相关信息。采用了kernel workqueue的工作模式,提供了数据传输相关的回调接口:transfer()接口用于将spi_message加入消息队列,workqueue从消息队列中取出spi_message,通过transfer_one_message()接口发送一个spi_message,每个spi_message包含多个spi_transfer,最终通过transfer_one()接口发送一个spi_transfer。

struct spi_master {

struct device    dev;

struct list_head list;

/* other than negative (== assign one dynamically), bus_num is fully

* board-specific.  usually that simplifies to being SOC-specific.

* example:  one SOC has three SPI controllers, numbered 0..2,

* and one board's schematics might show it using SPI-2.  software

* would normally use bus_num=2 for that controller.

*/

s16            bus_num;    // 总线编号

/* chipselects will be integral to many controllers; some others

* might use board-specific GPIOs.

*/

u16            num_chipselect;    // 片选个数

/* some SPI controllers pose alignment requirements on DMAable

* buffers; let protocol drivers know about these requirements.

*/

u16            dma_alignment;

/* spi_device.mode flags understood by this controller driver */

u16            mode_bits;

/* bitmask of supported bits_per_word for transfers */

u32            bits_per_word_mask;    // 一个transfer的bit数掩码

#define SPI_BPW_MASK(bits) BIT((bits) - 1)

#define SPI_BIT_MASK(bits) (((bits) == 32) ? ~0U : (BIT(bits) - 1))

#define SPI_BPW_RANGE_MASK(min, max) (SPI_BIT_MASK(max) - SPI_BIT_MASK(min - 1))

/* limits on transfer speed */

u32            min_speed_hz;    // 支持的最小传输速率

u32            max_speed_hz;    // 支持的最大传输速率

/* other constraints relevant to this driver */

u16            flags;

#define SPI_MASTER_HALF_DUPLEX    BIT(0)        /* can't do full duplex */

#define SPI_MASTER_NO_RX    BIT(1)        /* can't do buffer read */

#define SPI_MASTER_NO_TX    BIT(2)        /* can't do buffer write */

#define SPI_MASTER_MUST_RX      BIT(3)        /* requires rx */

#define SPI_MASTER_MUST_TX      BIT(4)        /* requires tx */

/* lock and mutex for SPI bus locking */

spinlock_t        bus_lock_spinlock;

struct mutex        bus_lock_mutex;

/* flag indicating that the SPI bus is locked for exclusive use */

bool            bus_lock_flag;

/* Setup mode and clock, etc (spi driver may call many times).

*

* IMPORTANT:  this may be called when transfers to another

* device are active.  DO NOT UPDATE SHARED REGISTERS in ways

* which could break those transfers.

*/

int            (*setup)(struct spi_device *spi);    // 每个transfer传输之前由 spi_driver调用,用于配置传输参数(不同从设备在速率和时钟模式上都可能不同,因此每个transfer都需要重新配置)

/* bidirectional bulk transfers

*

* + The transfer() method may not sleep; its main role is

*   just to add the message to the queue.

* + For now there's no remove-from-queue operation, or

*   any other request management

* + To a given spi_device, message queueing is pure fifo

*

* + The master's main job is to process its message queue,

*   selecting a chip then transferring data

* + If there are multiple spi_device children, the i/o queue

*   arbitration algorithm is unspecified (round robin, fifo,

*   priority, reservations, preemption, etc)

*

* + Chipselect stays active during the entire message

*   (unless modified by spi_transfer.cs_change != 0).

* + The message transfers use clock and SPI mode parameters

*   previously established by setup() for this device

*/

int            (*transfer)(struct spi_device *spi,

struct spi_message *mesg);    // spi_async() / spi_sync() 接口调用该方法将spi_message消息加入队列

/* called on release() to free memory provided by spi_master */

void            (*cleanup)(struct spi_device *spi);

/*

* Used to enable core support for DMA handling, if can_dma()

* exists and returns true then the transfer will be mapped

* prior to transfer_one() being called.  The driver should

* not modify or store xfer and dma_tx and dma_rx must be set

* while the device is prepared.

*/

bool            (*can_dma)(struct spi_master *master,

struct spi_device *spi,

struct spi_transfer *xfer);

/*

* These hooks are for drivers that want to use the generic

* master transfer queueing mechanism. If these are used, the

* transfer() function above must NOT be specified by the driver.

* Over time we expect SPI drivers to be phased over to this API.

*/

bool                queued;

struct kthread_worker        kworker;

struct task_struct        *kworker_task;

struct kthread_work        pump_messages;    // work queue,用于处理队列中的spi_message

spinlock_t            queue_lock;

struct list_head        queue;

struct spi_message        *cur_msg;

bool                idling;

bool                busy;

bool                running;

bool                rt;

bool                auto_runtime_pm;

bool                            cur_msg_prepared;

bool                cur_msg_mapped;

struct completion               xfer_completion;

size_t                max_dma_len;

int (*prepare_transfer_hardware)(struct spi_master *master);      // 准备好硬件,用于实际数据传输

int (*transfer_one_message)(struct spi_master *master,

struct spi_message *mesg);                                            // 发送一个spi_message

int (*unprepare_transfer_hardware)(struct spi_master *master);

int (*prepare_message)(struct spi_master *master,

struct spi_message *message);

int (*unprepare_message)(struct spi_master *master,

struct spi_message *message);

/*

* These hooks are for drivers that use a generic implementation

* of transfer_one_message() provied by the core.

*/

void (*set_cs)(struct spi_device *spi, bool enable);    // 每次传输前,设置片选信号

int (*transfer_one)(struct spi_master *master, struct spi_device *spi,

struct spi_transfer *transfer);                          // 发送一个 spi_transfer

void (*handle_err)(struct spi_master *master,

struct spi_message *message);

/* gpio chip select */

int            *cs_gpios;

/* statistics */

struct spi_statistics    statistics;

/* DMA channels for use with core dmaengine helpers */

struct dma_chan        *dma_tx;

struct dma_chan        *dma_rx;

/* dummy data for full duplex devices */

void            *dummy_rx;

void            *dummy_tx;

};

(2)struct spi_device:spi_device用于描述一个spi从设备,一般在主设备注册时,通过平台相关代码配置或者设备树配置自动创建并注册。

struct spi_device {

struct device        dev;

struct spi_master    *master;

u32            max_speed_hz;    // 支持的最大传输速率

u8            chip_select;    // 片选

u8            bits_per_word;    // 单位传输bit数

u16            mode;    // 工作模式

#define    SPI_CPHA    0x01            /* clock phase */

#define    SPI_CPOL    0x02            /* clock polarity */

#define    SPI_MODE_0    (0|0)            /* (original MicroWire) */

#define    SPI_MODE_1    (0|SPI_CPHA)

#define    SPI_MODE_2    (SPI_CPOL|0)

#define    SPI_MODE_3    (SPI_CPOL|SPI_CPHA)

#define    SPI_CS_HIGH    0x04            /* chipselect active high? */

#define    SPI_LSB_FIRST    0x08            /* per-word bits-on-wire */

#define    SPI_3WIRE    0x10            /* SI/SO signals shared */

#define    SPI_LOOP    0x20            /* loopback mode */

#define    SPI_NO_CS    0x40            /* 1 dev/bus, no chipselect */

#define    SPI_READY    0x80            /* slave pulls low to pause */

#define    SPI_TX_DUAL    0x100            /* transmit with 2 wires */

#define    SPI_TX_QUAD    0x200            /* transmit with 4 wires */

#define    SPI_RX_DUAL    0x400            /* receive with 2 wires */

#define    SPI_RX_QUAD    0x800            /* receive with 4 wires */

int            irq;

void            *controller_state;

void            *controller_data;

char            modalias[SPI_NAME_SIZE];

int            cs_gpio;    /* chip select gpio */

/* the statistics */

struct spi_statistics    statistics;

/*

* likely need more hooks for more protocol options affecting how

* the controller talks to each chip, like:

*  - memory packing (12 bit samples into low bits, others zeroed)

*  - priority

*  - drop chipselect after each word

*  - chipselect delays

*  - ...

*/

};

(3)struct spi_driver:从设备驱动

struct spi_driver {

const struct s

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值