当前位置: 首页 > Linux

嵌入式Linux系统的开发——SPIBit-banging方法的实现

时间:2023-04-06 19:02:21 Linux

前言SPI(SerialPeripheralInterface)是一种应用广泛的通信总线。通常,微处理器会集成一个SPI模块来支持通信协议。输出正确信号的时序,并保证时序之间的同步,实现与外部SPI设备的正常通信。当需要在微处理器上使用SPI模块,但发现管脚被占用时,可以使用SPIBit-banging的方法,通过GPIO端口。实现SPI协议,与对应的SPI设备通信。下面是MT7688芯片的SPI读写时序图。本文主要介绍如何在嵌入式linux分发平台上实现SPIBit-banging功能。设备树语法和格式嵌入式linux系统引入了设备树(DeviceTree)机制,利用这种数据结构将硬件信息组织成DTS(DeviceTreesource)文件,用于描述板级设备。设备树由基本单元——节点组织成树状结构。一棵设备树只有一个根节点(rootnode)。根节点可以包含多个子节点,每个子节点可以同时包含多个属性和子级节点。子节点,属性用于描述节点的具体特征。下面是.dts文件中最基本的树结构,“/”表示根节点,根节点下的两个子节点分别为“node1”和“node2”,分别为“node1”和“node2”分别包含子节点,如“child-node1”和“child-node2”。文件中的几个键值对是分散在设备树中的属性。/{node1{a-string-property="一个字符串";a-string-list-property="第一个字符串","第二个字符串";a-byte-data-property=[0x010x230x340x56];child-node1{first-child-property;第二个孩子属性=<1>;a-string-property="你好,世界";};子节点2{};};node2{一个空属性;单元格属性=<1234>;/*每个数字(单元格)都是一个uint32*/child-node1{};};};由于上面的.dts文件没有描述任何硬件设备的特性,下面以openwrtrelease版本上的MT7628dts文件为例,对设备树进行详细描述。每个节点以“<名称>[@<设备地址>]”的形式命名,当节点描述的设备有设备地址时,需要在名称后加上主地址,节点使用reg=方法列出设备使用的地址范围,父节点的#address-cells和#size-cells属性声明reg中的字段数。节点中的compatible属性表示使用哪个设备驱动绑定到当前节点描述的设备上。Mt7628an.dtsi文件部分代码:/{#address-cells=<1>;#size-cells=<1>;compatible="ralink,mtk7628an-soc";cpus{cpu@0{compatible="mips,mips24KEc";};};选择{bootargs="console=ttyS0,57600";};......掌上电脑:palmbus@10000000{compatible="palmbus";reg=<0x100000000x200000>;范围=<0x00x100000000x1FFFFF>;#address-cells=<1>;#size-cells=<1>;sysc:sysc@0{compatible="ralink,mt7620a-sysc";reg=<0x00x100>;};gpio@600{#address-cells=<1>;#size-cells=<0>;compatible="mtk,mt7628-gpio","mtk,mt7621-gpio";reg=<0x6000x100>;中断父母=<&intc>;中断=<6>;gpio0:bank@0{reg=<0>;compatible="mtk,mt7621-gpio-bank";gpio控制器;#gpio-cells=<2>;};gpio1:bank@1{reg=<1>;compatible="mtk,mt7621-gpio-bank";gpio控制器;#gpio-cells=<2>;};gpio2:bank@2{reg=<2>;compatible="mtk,mt7621-gpio-bank";gpio控制器;#gpio-cells=<2>;};};spi0:spi@b00{compatible="ralink,mt7621-spi";reg=<0xb000x100>;重置=<&rstctrl18>;重置名称=“spi”;#address-cells=<1>;#size-cells=<0>;pinctrl-名称=“默认”;pinctrl-0=<&spi_pins>;状态=“禁用”;};......};pinctrl:pinctrl{compatible="ralink,rt2880-pinmux";pinctrl-名称=“默认”;pinctrl-0=<&state_default>;state_default:pinctrl0{};spi_pins:spi{spi{ralink,group="spi";“spi”;};};spi_cs1_pins:spi_cs1{spi_cs1{ralink,group="spics1";ralink,函数=“spics1”;};};......};};SPIBit-banging嵌入式Linux内核中提供了SPIBit-banging驱动代码的实现,只需要配置相应的配置即可使用。节点中spis函数的引脚在pinctrl中声明为GPIO引脚,驱动文件为drivers/spi路径下的spi-gpio.c,函数中注册的驱动名称为spi_gpio,对应兼容属性dts文件的部分代码:gpio-spi{status="okay";兼容=“spi-gpio”;#address-cells=<0x1>;范围;gpio-sck=<&gpio0141>;gpio-miso=<&gpio0151>;gpio-mosi=<&gpio0161>;cs-gpios=<&gpio0171>;num-chipselects=<1>;}spi-gpio.c文件的部分代码:#defineDRIVER_NAME"spi_gpio"staticstructplatform_driverspi_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的配置界面中选择Kernelmodules–>SPISupport–>kmod-spi-gpio,之后会自动关联kmod-spi-bitbang模块选择。最后编译内核并烧录固件。内核启动后,使用lsmod命令查看加载到内核中的模块状态信息,可以发现spi_bitbang和spi_gpio模块已经加载到内核中。在spi-gpio.c文件的spi_gpio_probe函数中加入printk语句,观察启动时spi-gpio驱动加载运行,从dts文件中获取定义为SPIBit-banging函数的GPIO引脚。结语SPI的bit-bang方式虽然可以不依赖控制器上的SPI外设模块实现SPI协议,但是需要代码来完成时序逻辑和同步要求。相对而言,性能低于控制器本身的SPI模块,因此只适用于对速度要求不高的应用。