SPI子系统驱动架构 - 驱动框架

文章系列

SPI子系统驱动架构 - 简介

SPI子系统驱动架构 - 驱动框架

SPI子系统驱动架构 - 具体实现

SPI驱动框架

spi驱动框架如图所示,驱动框架分用户层、核心层和硬件层,用户层主要向上层开发人员提供接口,硬件层是spi模块和spi设备的硬件描述,我们主要认识核心层spi-core。

核心层中分设备层和控制器层,设备层提供spi从设备的注册,控制器层提供芯片spi控制模块的注册,一般控制器层的驱动在内核中都已经提供了,我们主要是编写自己的设备驱动,具体编写就可以参考别的器件的驱动。从图中我们可以看到控制器层有spi_master和spi_bitbang两个结构体代表控制器模块,区别在于spi_bitbang会提供一种机制,而这种机制是spi_master注册时没有的,具体下文介绍。在整个设备的注册流程中,系统驱动后会先注册控制器的驱动,然后会注册挂在spi总线上的设备层的驱动。

这里写图片描述

spi驱动的代码都在drivers/spi/目录下,进去后感觉乱糟糟的,不像i2c那样分的清楚,不过代码看多了之后就清楚了,呵呵。主要的文件是spi.c和spi-bitbang.c,这些都是核心文件,spidev.c是一个设备层的文件,其他大多是控制器代码文件。

SPI主控制器(总线)驱动介绍

spi主控制器的注册是通过platform bus来进行的,在系统初始化时会进行spi的platform_device的注册,然后具体SoC上的spi模块的platform_driver的注册在各自的文件中,注册匹配后就会进入probe函数来进行spi主控制器spi_master的注册,相关结构体下面介绍

结构体介绍

spi_master定义了SPI主控制器,spi_transfer 和spi_message 是数据传输时使用的结构体,spi_transfer的链表挂在spi_message 的链表中,所以每次数据传输时,一个spi_message 会有多个spi_transfer来进行传输,每次进行数据传输时,都会检查spi_message 的状态,看是否合适进行传输

struct spi_master {
    struct device   dev;
    struct list_head list;
    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;
    /* limits on transfer speed */
    u32         min_speed_hz;
    u32         max_speed_hz;
    /* other constraints relevant to this driver */
    u16         flags;
    /*
     * on some hardware transfer size may be constrained
     * the limit may depend on device transfer settings
     */
    size_t (*max_transfer_size)(struct spi_device *spi);
    /* 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;
    int         (*setup)(struct spi_device *spi);
    int         (*transfer)(struct spi_device *spi,
                        struct spi_message *mesg);
    /* called on release() to free memory provided by spi_master */
    void            (*cleanup)(struct spi_device *spi);
    bool            (*can_dma)(struct spi_master *master,
                       struct spi_device *spi,
                       struct spi_transfer *xfer);
    bool                queued;
    struct kthread_worker       kworker;
    struct task_struct      *kworker_task;
    struct kthread_work     pump_messages;
    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);
    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);
    int (*spi_flash_read)(struct  spi_device *spi,
                  struct spi_flash_read_message *msg);

    /*
     * 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);
    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;

    int (*fw_translate_cs)(struct spi_master *master, unsigned cs);
};
struct spi_transfer {
    const void  *tx_buf;
    void        *rx_buf;
    unsigned    len;

    dma_addr_t  tx_dma;
    dma_addr_t  rx_dma;
    struct sg_table tx_sg;
    struct sg_table rx_sg;

    unsigned    cs_change:1;
    unsigned    tx_nbits:3;
    unsigned    rx_nbits:3;

    u8      bits_per_word;
    u16     delay_usecs;
    u32     speed_hz;

    struct list_head transfer_list;
};
struct spi_message {
    struct list_head    transfers;

    struct spi_device   *spi;

    unsigned        is_dma_mapped:1;

    /* completion is reported through a callback */
    void            (*complete)(void *context);
    void            *context;
    unsigned        frame_length;
    unsigned        actual_length;
    int         status;

    struct list_head    queue;
    void            *state;

    /* list of spi_res reources when the spi message is processed */
    struct list_head        resources;
};

spi_bitbang是另一套主控制器结构体,它提供一种数据传输机制,struct spi_bitbang其实就是包装了spi_maser

struct spi_bitbang {
    spinlock_t      lock;
    u8          busy;
    u8          use_dma;
    u8          flags;      /* extra spi->mode support */

    struct spi_master   *master;

    /* setup_transfer() changes clock and/or wordsize to match settings
     * for this transfer; zeroes restore defaults from spi_device.
     */
    int (*setup_transfer)(struct spi_device *spi,
            struct spi_transfer *t);

    void    (*chipselect)(struct spi_device *spi, int is_on);
#define BITBANG_CS_ACTIVE   1   /* normally nCS, active low */
#define BITBANG_CS_INACTIVE 0

    /* txrx_bufs() may handle dma mapping for transfers that don't
     * already have one (transfer.{tx,rx}_dma is zero), or use PIO
     */
    int (*txrx_bufs)(struct spi_device *spi, struct spi_transfer *t);

    /* txrx_word[SPI_MODE_*]() just looks like a shift register */
    u32 (*txrx_word[4])(struct spi_device *spi,
            unsigned nsecs,
            u32 word, u8 bits);
};

函数介绍

spi主控制器设备驱动注册与卸载函数

extern int spi_register_master(struct spi_master *master);

extern void spi_unregister_master(struct spi_master *master);

现在进行spi主控制器设备的注册一般使用下面的函数,对应于struct spi_bitbang,使用这个函数进行注册会开启开启线程来进行spi数据传输

extern int spi_bitbang_start(struct spi_bitbang *spi);

extern void spi_bitbang_stop(struct spi_bitbang *spi);

SPI设备驱动介绍

结构体介绍

spi_device 等同于驱动模型中的device

struct spi_device {
    struct device       dev;
    struct spi_master   *master;
    u32         max_speed_hz;
    u8          chip_select;
    u8          bits_per_word;
    u16         mode;
    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;


};

spi_driver 等同于驱动模型中的driver

struct spi_driver {
    const struct spi_device_id *id_table;
    int         (*probe)(struct spi_device *spi);
    int         (*remove)(struct spi_device *spi);
    void            (*shutdown)(struct spi_device *spi);
    struct device_driver    driver;
};

函数介绍

spi从设备驱动driver注册与卸载函数

spi_register_driver(driver)
spi_unregister_driver()

spi从设备device注册与卸载函数

extern struct spi_device *
spi_alloc_device(struct spi_master *master);

extern int
spi_add_device(struct spi_device *spi);

extern struct spi_device *
spi_new_device(struct spi_master *, struct spi_board_info *);

extern void spi_unregister_device(struct spi_device *spi);
  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在STM32单片机上使用硬件SPI驱动4线SPI-LCD的方法如下: 1. 首先,确保你已经连接好了STM32单片机和LCD屏幕,并且正确配置了SPI引脚。 2. 在代码中包含SPI库和LCD库的头文件。例如,对于ST7735驱动的LCD屏幕,你可以包含"ST7735.h"头文件。 3. 初始化SPI和LCD屏幕。在初始化之前,你需要设置背景色和画笔色。这些颜色将用于绘制图形和文本。 4. 使用SPI发送命令和数据给LCD屏幕。你可以使用SPI的发送函数来发送命令和数据。具体的命令和数据可以参考LCD屏幕的数据手册。 5. 在LCD屏幕上绘制图形和文本。你可以使用LCD库提供的函数来绘制图形和文本。例如,你可以使用画线函数来绘制线条,使用填充矩形函数来绘制矩形,使用显示字符函数来显示文本等等。 6. 最后,关闭SPI和LCD屏幕。在程序结束之前,记得关闭SPI和LCD屏幕以释放资源。 下面是一个示例代码,演示了如何使用硬件SPI驱动4线SPI-LCD: ```c #include "ST7735.h" #include "usart.h" u16 BACK_COLOR, POINT_COLOR; //背景色,画笔色 void WriteCommand_7735(u8 cmd) { // 使用SPI发送命令给LCD屏幕 // ... } void WriteData_7735(u8 data) { // 使用SPI发送数据给LCD屏幕 // ... } void InitLCD() { // 初始化SPI和LCD屏幕 // ... } void DrawGraphics() { // 在LCD屏幕上绘制图形和文本 // ... } int main() { // 设置背景色和画笔色 BACK_COLOR = WHITE; POINT_COLOR = BLACK; // 初始化SPI和LCD屏幕 InitLCD(); // 在LCD屏幕上绘制图形和文本 DrawGraphics(); // 关闭SPI和LCD屏幕 // ... return 0; } ```

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值