linux控制spi文件,嵌入式linux系统的开发——SPI Bit-banging方法的实现

前言

SPI(Serial Peripheral Interface)是一种应用广泛的通信总线,通常微处理器上会集成SPI模块以支持该通信协议,输出正确的信号的时序,并保证时序间同步,实现与外部SPI设备正常通信。当需要使用微处理器上SPI模块,但发现引脚被占用时,那么可以通过SPI Bit-banging这个方法,通过GPIO端口模拟SPI接口引脚(CS、MOSI、MISO、CLK)上的时序信号来实现SPI协议,与对应SPI设备进行通信。以下为MT7688芯片的SPI读写时序图。本文主要介绍如何在嵌入式linux发行版平台上实现SPI Bit-banging功能。

AAffA0nNPuCLAAAAAElFTkSuQmCC

设备树语法和格式

嵌入式linux系统引入了设备树(Device Tree)机制,采用这种数据结构将硬件信息组织成DTS(Device Tree source)文件用于描述板级设备。设备树由基本单元——节点(node)组织成树状结构,一个设备树只有一个根节点(root node),根节点中可包含若干子节点,每个子节点可以同时包含若干属性和下一级子节点,属性用于描述了节点的具体特征。

以下为.dts文件中最基本的树结构,“/”表示根节点,根节点下的两个子节点分别为“node1”和“node2”,“node1”和“node2”又各自包含了子节点,如“child-node1”和“child-node2”。文件中若干键-值对,为分散在设备树中的属性。

/ {

node1 {

a-string-property = "A string";

a-string-list-property = "first string", "second string";

a-byte-data-property = [0x01 0x23 0x34 0x56];

child-node1 {

first-child-property;

second-child-property = <1>;

a-string-property = "Hello, world";

};

child-node2 {

};

};

node2 {

an-empty-property;

a-cell-property = <1 2 3 4>; /* each number (cell) is a uint32 */

child-node1 {

};

};

};

Mt7628an.dtsi文件部分代码:

/ {

#address-cells = <1>;

#size-cells = <1>;

compatible = "ralink,mtk7628an-soc";

cpus {

cpu@0 {

compatible = "mips,mips24KEc";

};

};

chosen {

bootargs = "console=ttyS0,57600";

};

......

palmbus: palmbus@10000000 {

compatible = "palmbus";

reg = <0x10000000 0x200000>;

ranges = <0x0 0x10000000 0x1FFFFF>;

#address-cells = <1>;

#size-cells = <1>;

sysc: sysc@0 {

compatible = "ralink,mt7620a-sysc";

reg = <0x0 0x100>;

};

gpio@600 {

#address-cells = <1>;

#size-cells = <0>;

compatible = "mtk,mt7628-gpio", "mtk,mt7621-gpio";

reg = <0x600 0x100>;

interrupt-parent = ;

interrupts = <6>;

gpio0: bank@0 {

reg = <0>;

compatible = "mtk,mt7621-gpio-bank";

gpio-controller;

#gpio-cells = <2>;

};

gpio1: bank@1 {

reg = <1>;

compatible = "mtk,mt7621-gpio-bank";

gpio-controller;

#gpio-cells = <2>;

};

gpio2: bank@2 {

reg = <2>;

compatible = "mtk,mt7621-gpio-bank";

gpio-controller;

#gpio-cells = <2>;

};

};

spi0: spi@b00 {

compatible = "ralink,mt7621-spi";

reg = <0xb00 0x100>;

resets = ;

reset-names = "spi";

#address-cells = <1>;

#size-cells = <0>;

pinctrl-names = "default";

pinctrl-0 = ;

status = "disabled";

};

......

};

pinctrl: pinctrl {

compatible = "ralink,rt2880-pinmux";

pinctrl-names = "default";

pinctrl-0 = ;

state_default: pinctrl0 {

};

spi_pins: spi {

spi {

ralink,group = "spi";

ralink,function = "spi";

};

};

spi_cs1_pins: spi_cs1 {

spi_cs1 {

ralink,group = "spi cs1";

ralink,function = "spi cs1";

};

};

......

};

};

SPI Bit-banging实现

嵌入式Linux内核中已提供SPI Bit-banging驱动代码,只需进行对应的配置即可使用。

首先在openwrt_widora-master/target/linux/ramips/dts路径下修改Widora.dts文件,将配置代码加入根节点中,并且在pinctrl中将Spis功能的引脚申明为GPIO引脚,驱动文件为/drivers/spi路径下的spi-gpio.c,函数中注册的驱动名称为spi_gpio,与 compatible属性对应。

dts文件部分代码:

gpio-spi {

status = "okay";

compatible = "spi-gpio";

#address-cells = <0x1>;

ranges;

gpio-sck = ;

gpio-miso = ;

gpio-mosi = ;

cs-gpios = ;

num-chipselects = <1>;

}

pinctrl {

state_default: pinctrl0 {

spis {

ralink,group = "spis";

ralink,function = "gpio";

};

......

};

};

spi-gpio.c文件部分代码:

#define DRIVER_NAME "spi_gpio"

static struct platform_driver spi_gpio_driver = {

.driver = {

.name = DRIVER_NAME,

.owner = THIS_MODULE,

.of_match_table = of_match_ptr(spi_gpio_dt_ids),

},

.probe = spi_gpio_probe,

.remove = spi_gpio_remove,

};

module_platform_driver(spi_gpio_driver);

其次在OpenWrt的配置界面中选择Kernel modules–> SPI Support –>kmod-spi-gpio,选中后会自动关联 kmod-spi-bitbang模块。

AAffA0nNPuCLAAAAAElFTkSuQmCC

最后编译内核并烧录固件。内核启动后通过lsmod命令查看已经加载到内核中的模块的状态信息,可发现内核已经加载了spi_bitbang和spi_gpio模块

AAffA0nNPuCLAAAAAElFTkSuQmCC

在spi-gpio.c文件的spi_gpio_probe函数加入printk语句观察可获悉到spi-gpio驱动在启动时被加载运行,并且从dts文件中获取到定义为SPI Bit-banging功能的GPIO引脚。

AAffA0nNPuCLAAAAAElFTkSuQmCC

结论

SPI的bit-bang方式实现SPI协议虽然可以不依赖于控制器上的SPI外设模块,但是需要代码完成时序逻辑和同步要求,相对来说性能低于控制器自身的SPI模块,因此仅适用于低速要求的应用场合。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值