SPI 学习总结

来源:互联网 发布:设计图纸软件下载 编辑:程序博客网 时间:2024/06/02 00:58


1. SPI 简介
SPI (Serial Peripheral interface)串行外围设备接口,是Motorola首先在其MC68HCXX系列处理器上定义的。
SPI接口主要应用在 EEPROM,FLASH,实时时钟,AD转换器,还有数字信号处理器和数字信号解码器之间。
SPI是一种高速的,全双工,同步的通信总线,并且在芯片的管脚上只占用四根线,节约了芯片的管脚,同时为PCB的布局上节省空间,提供方便。
SPI的四根线为SDI(数据输入),SDO(数据输出),SCLK(时钟),CS(片选)。
      可以参考 drivers/spi 目录。      
spi_device的板信息用spi_board_info结构体来描述:
struct spi_board_info {
    char    modalias[SPI_NAME_SIZE];
    const void    *platform_data;
    void    *controller_data;
    int    irq;
    u32    max_speed_hz;
    u16    bus_num;
    u16    chip_select;
    u8    mode;
};
记录了SPI外设使用的主机控制器序号、片选信号、数据比特率、SPI传输方式等
static struct mcp251x_platform_data mcp251x_info = {
        .oscillator_frequency = 20*1000*1000, /*外部晶振,结合手册及具体硬件设置*/
        .board_specific_setup = NULL,  
        .power_enable = NULL,  
        .transceiver_enable = NULL,
};
CS用gpio替换
static struct pxa2xx_spi_chip qrk_ffrd_spi_cs_mcp251x = {
    .gpio_cs = 9,/*GPIO号*/
};
    {
        .modalias = "mcp2515",
        .platform_data = &mcp251x_info,
        .mode = SPI_MODE_0,
        .irq = 58,
        .max_speed_hz = 2*1000*1000,       /* max sample rate at 3V */
        .bus_num = 0,
        .chip_select = 1,
        .controller_data = &qrk_ffrd_spi_cs_mcp251x,
     }
spi_register_board_info(spi_devs, ARRAY_SIZE(spi_devs));

     MOSI(SDO):主器件数据输出,从器件数据输入。

      MISO(SDI):主器件数据输入,从器件数据输出。

      SCLK :时钟信号,由主器件产生。

      CS:从器件使能信号,由主器件控制(可以使用GPIO来替换)。

      SPI是串行通讯协议,也就是说数据是一位一位从MSB或者LSB开始传输的,这就是SCK时钟线存在的原因,由SCK提供时钟脉冲,MISO、MOSI则基于此脉冲完成数据传输。 SPI支持4-32bits的串行数据传输,支持MSB和LSB,每次数据传输时当从设备的大小端发生变化时需要重新设置SPI Master的大小端。

2 SPI 驱动架构

      SPI的驱动架构分为三个层次:SPI 核心、SPI控制器驱动和SPI设备驱动。

SPI核心:

      主要提供了核心数据结构的定义、SPI控制器驱动和设备驱动的注册、注销管理等的API接口。

SPI控制器驱动:

    每种平台都有自己的控制器,可参考处理器手册移植。其功能是为每条SPI总线实现读写方法,向下连接SPI从设备。

   在include/liunx/spi/spi.h文件中,在数据结构struct spi_master定义如下:

 

  1. struct spi_master {  

  2.     struct device   dev;  

  3.     s16         bus_num;  

  1.     u16         num_chipselect;  

  2.     int         (*setup)(struct spi_device *spi);  

  3.     int         (*transfer)(struct spi_device *spi, struct spi_message *mesg);  

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

  5. };  

     bus_num        对应的SPI总线号。

      num_chipselect     能支持的spi设备个数 

      setup        设置SPI总线的模式,时钟等的初始化函数,在spi_add_device函数中调用。 

      transfer    函数是实现SPI总线读写方法的函数。实现数据的双向传输.

    cleanup        注销时候调用

SPI设备驱动:

    为应用层提供通过SPI总线访问设备的接口。

     使用到两个模块来实现。

 1. struct spi_driver 注册扫描SPI总线上的设备,通过probe来匹配对应的设备并进行初始化设备。

    struct spi_driver {  

        int         (*probe)(struct spi_device *spi);  

        int         (*remove)(struct spi_device *spi);  

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

        int         (*suspend)(struct spi_device *spi, pm_message_t mesg);  

        int         (*resume)(struct spi_device *spi);  

        struct device_driver    driver;  

    }; 

    具体的实现可以参考spi的slave驱动。


2. struct spi_device 的构建与注册

    struct spi_device {  

        struct device       dev;  

        struct spi_master   *master;  

        u32         max_speed_hz;  

        u8          chip_select;  

        u8          mode;    

        u8          bits_per_word;  

        int         irq;  

        void            *controller_state;  

        void            *controller_data;  

        char            modalias[32];   

    }; 

 spi_device 对应于特定的从设备,并且spi_device 封装了一个spi_master结构体。

spi_device 的赋值在platform文件中完成。

以设备mcp2515,spi转CAN为例:


mcp2515从设备平台信息

static struct spi_board_info spi_devs[]={

};


 在platform的init函数中调用.

 注册把spi_board_info注册到board_list.在spi_master注册中调用scan_boardinfo扫描board_list并匹配设备,然后创建并注册spi_deivce.

 参考:

http://www.cnblogs.com/liugf05/archive/2012/12/03/2800457.html

 

0 0
原创粉丝点击