一、spi 控制器驱动spi控制器驱动通常由硬件设备制造商提供,他们为不同的操作系统(如linux、windows、rtos等)编写不同的驱动程序。驱动程序的主要功能是管理spi控制器,向外部设备发送和接收数据,并提供对spi接口的访问。
spi控制器驱动需要实现以下功能:
初始化spi控制器:驱动程序需要初始化spi控制器,设置通信速率、数据位宽、时钟极性和相位等参数。控制spi接口:驱动程序需要控制spi接口,包括选择片选信号、发送和接收数据、等待传输完成等。支持多线程:驱动程序需要支持多线程访问spi接口,以便多个应用程序可以同时使用spi接口进行通信。
但是spi 控制器驱动本身不会直接提供接口给应用操作。基于linux kernel 5.15
二、spi 控制器驱动注册要记住spi控制器是芯片资源,cpu能直接寻址,因此使用的总线是platform总线。而spi设备是外部设备,是使用spi_bus_type。
spi 控制器驱动中涉及spi_master和spi_bitbang两个对象,从spi_bitbang可以找到spi_master。
以上两个对象设置后之后,就可以使用以下接口注册,会完成大量初始化操作。
使用bitbang注册接口int spi_bitbang_start(struct spi_bitbang *bitbang) int spi_bitbang_init(struct spi_bitbang *bitbang) int spi_register_master(struct spi_controller *ctlr)什么是bitbang接口,暂时不知道,只知道是比较新的注册方式。
当使用这种接口的时候:
spi_bitbang_init()做的事情spi_master不能提供transfer和transfer_one_message方法。如果使用硬件spi提供的cs片选,那么需要spi_bitbang提供chipselect方法,同时会spi_master→set_cs使用spi_bitbang_set_cs里面去调用spi_bitbang提供chipselect方法。spi_master->use_gpio_descriptors表示使用gpio cs而不是硬件csspi_bitbang→txrx_bufs方法如果不提供,那么spi core认为你不需要使用dma传输spi数据。同时设置一些默认写好的的方法:spi_bitbang- >txrx_bufs = spi_bitbang_bufs//如果spi_bitbang- >setup没有提供,则使用默认spi_bitbang- >setup_transfer =spi_bitbang_setup_transfer;spi_master- >setup = spi_bitbang_setup;spi_master- >cleanup = spi_bitbang_cleanup;master这几个接口一定会使用默认写好的方法:spi_master- >prepare_transfer_hardware = spi_bitbang_prepare_hardware;spi_master- >unprepare_transfer_hardware = spi_bitbang_unprepare_hardware;spi_master- >transfer_one = spi_bitbang_transfer_one;//在初始化队列spi_controller_initialize_queue()的时候spi_master- >transfer = spi_queued_transferspi_master- >- >transfer_one_message = spi_transfer_one_messagespi_register_master()做的事情spi控制器硬件分为主机模式和从机模式,使用spi_controller来表示,实际上也就是spi_master。他们在使用api方面有区别。
处理spi总线号 ,如spi1、spi2中的数字,主要是根据设备树的alias处理cs-gpios片选属性 ,根据设备树中对cs-gpios片选属性的描述,更新spi_master→num_chipselect,分配所有gpio描述符,spi_master→cs_gpiods保存着所有gpio描述符,如在spi控制器设备树节点中使用的。&ecspi2{ ... cs-gpios = ,;//gpio1_29 ...增加master默认回调 ,继续给spi_master增加默认写好的方法spi_master- >transfer = spi_queued_transfer;spi_master- >transfer_one_message = spi_transfer_one_message;创建工作队列 ,使整个spi架构运转起来,可以ps -e命令看到如下内核线程信息
彩蛋,还可以给这个工作队列的内核线程设置实时调度策略降低总线延迟。
创建spi_device ,**最后最重要的是of_register_spi_devices()**处理spi控制器设备树下的所有spi设备子节点,这就是spi_device的由来,spi_device表示一个spi设备,如oled等。一个spi总线下面可以挂接多个spi设备。&ecspi2{ fsl,spi-num-chipselects = ; cs-gpios = ;//gpio1_29 pinctrl-names = default; pinctrl-0 = ; num-cs = ; status = okay; oled: ssd13306@0{ compatible = alientek,ssd13306;//自己写的oled驱动 spi-cpha; spi-cpol; spi-max-frequency = ; reset-gpios = ; dc-gpios = ; reg = ; };};比较重要的设备树解析在of_spi_parse_dt(),关键的属性spi_device的字段对应如下:
属性描述
spi-cpha spi->mode = spi_cpha cpha=1
spi-cpol spi->mode = spi_cpol cpol=1
spi-3wire spi->mode = spi_3wire 使用三线spi
spi-lsb-first spi->mode = spi_lsb_first 一般spi是msb,指定后lsb
spi-cs-high spi->mode = spi_cs_high 一般片选cs是低有效,指定后高有效
spi-tx-bus-width spi->mode = spi_no_tx 发送方向为0,可能只是读
= spi_tx_dual dual spi 双线半双工
= spi_tx_quad quad spi 四线半双工
= spi_tx_octal octal spi 八线半双工
spi-rx-bus-width spi->mode = spi_no_rx 接受方向为0,可能只是发送
= spi_rx_dual dual spi 双线半双工
= spi_rx_quad quad spi 四线半双工
= spi_rx_octal octal spi 八线半双工
reg spi->chip_select 表示spi设备在第几个片选
spi-max-frequency spi->max_speed_hz 这个spi设备使用的spi传输速率,单位hz
multi-die spi->multi_die
slave” 判断spi控制器是否是从设备
以上属性都是spi_device的设备树属性,不是spi控制器的设备树属性。“reg”属性必须设置,表示片选。这个解析过程spi控制器驱动注册的时候交给spi core做的。
发起传输时候的回调顺序- >prepare_transfer_hardware(master) -------spi_bitbang_prepare_hardware() |- >prepare_message(master,msg)-----------bsp |- >transfer_one_message(msg)-----------spi_transfer_one_message() |- >transfer_one(master, spi_device,xfer)-----------spi_bitbang_transfer_one() |- >transfer_one |- >setup_transfer(spi_dev, xfer)------------bsp |- >txrx_bufs(spi_dev, xfer)-----------------bsp |- >transfer_one |- >transfer_one |- >transfer_one ...prepare_transfer_hardware :就是设置busy字段
prepare_message :包含了硬件初始化
①设置主从模式。
②配置硬件cs使能和是否高有效。
③配置cpah\\cpol。
transfer_one_message :spi_transfer_one_message(),针对一个spi_message
①拉低cs
②发送所有spi_transfer,每个spi_transfer之间会有延迟,人为通过spi_transfer→delay指定。每个spi_transfer也可以有cs转换,通过设置spi_transfer→cs_change
③拉高cs
transfer_one : spi_bitbang_transfer_one(),调用setup_transfer和txrx_bufs
setup_transfer :用来配置每一个spi_transfer
①对rx tx buf作对齐
②更新是否使用dma标志,也就是说每一段transfer都可以决定用不用dma
③设置字长和时钟,也就是说每一段transfer都可以单独设置sclk和字长
txrx_bufs :写fifo或者读fifo
①读空fifo
②发送tx_buf到txfifo,硬件操作,需要处理字节对齐
③等待tx 空中断,表明一个transfer发送完了
中断 :
①读rxfifo
②唤醒完成量
提出三个问题1.每个具体的spi设备指定的reg属性怎么对应spi控制器的cs片选?
答:在spi device注册的时候,会根据reg片选号拿到spi_master先前遍历的cs 片选gpiod描述符,取对应的那个,从cs_gpiods数组中拿。
static int __spi_add_device(struct spi_device *spi){ ... /* descriptors take precedence */ if (ctlr- >cs_gpiods) spi- >cs_gpiod = ctlr- >cs_gpiods[spi- >chip_select]; else if (ctlr- >cs_gpios) spi- >cs_gpio = ctlr- >cs_gpios[spi- >chip_select]; ...}2.每个具体的spi设备指定的spi通信速率,在哪里体现?
答:在spi_setup()最后检查,如果指定的速率大于spi控制器的速率,那么就使用spi控制器的速率
int spi_setup(struct spi_device *spi){ ... if (spi- >controller- >max_speed_hz && (!spi- >max_speed_hz || spi- >max_speed_hz > spi- >controller- >max_speed_hz)) spi- >max_speed_hz = spi- >controller- >max_speed_hz; ...}3.spi 设备在用户空间看到的名称格式
答:看到的名称格式是:%s.%u”。%s是spi控制器的名称,%u是片选。如spi1.0
root@imx6ull /sys/devices/platform/soc/2000000.bus/2000000.spba-bus/200c000.spi/spi_master/spi1# lsdevice power statistics ueventof_node spi1.0 subsystemspi_controller_list链表保存所有spi_master
spi_device不会单独被链表组织,会被kobject组织
至此,spi_bitbang_start完成之后,无论是spi_master还是其下面每个spi_device都已经初始化完成,但是要记住,spi设备驱动还没有进行,因为以上只是构造好了当前有什么设备,有什么控制器,但是对于spi设备来说,还需要针对他的驱动,这就是spi设备驱动。比如oled,在以上过程执行完之后,仅仅给oled抽象成了一个spi device,但是要如何控制oled,还需要这个oled驱动,进行oled的读写操作。
spi_master→setup 每个spi device注册进来的时候调用一次。
三大运营商5G商用套餐已经正式上线来了解流量够用吗?
疫情或将成推动5G手机发展的巨大利好
EDA软件断供对国产芯片发展有什么影响
在别墅区使用手机接收不到信号的原因是什么
新加坡制定人工智能自我评估指南
Linux SPI控制器驱动教程
总有一款适合你 萤石热销互联网摄像机推荐
如何选择合适的PCBA
高通公司在快速多样化的部署频谱和多样化的网络5G
模胚加工方法?塑胶模胚的正确选购方法有哪些?
可用于磁性编码器的霍尔速度方向芯片:中科阿尔法AH701(替代SS526DT)
高清D01商用案例:济南连城水岸小区来了新伙伴
串口的基本结构与通信方式
易控智驾露天矿无人驾驶运输解决方案荣获多个奖项认可
华米科技正式发布了新一代智能可穿戴芯片
采用西门子S7-300PLC和变频器实现焦炉鼓风机控制系统的设计
电磁流量计在使用时一般会出现哪些故障
人类正从工业文明走向数字文明 区块链和人工智能发展的拐点已至
JEEP自由光与奥迪Q5哪个好?一文了解两款车的区别
sip协议详细分析与实现