使用spi-gpio-custom模块配置SPI总线
来源 https://www.xuzhe.tj.cn/index.php/2023/10/26/spi-gpio-customspi/
参考专栏 https://www.zhihu.com/column/c_1698084667767709696
1. 引言
SPI(Serial Peripheral Interface)是一种常见的串行通信协议,广泛应用于微控制器与外部设备的连接。
Linux内核中的spi-gpio与spi-bitbang模块可使用GPIO引脚进行SPI的位操作,spidev模块可将SPI暴露给用户空间。但是,这些模块并不能“直接”使用:它们被其他内核驱动程序使用。没有办法动态地说“我想在这些引脚上使用一个SPI”。相反,我们需要重新配置、编译内核。
spi-gpio-custom模块允许动态配置SPI总线及其节点,无需重新编译内核。对于测试、概念验证非常方便。此外,spi-gpio-custom模块的速度也相当不错,测试显示它可以达到1 MHz以上。
2. 安装spi-gpio-custom
以openwrt系统为例,安装模块包是最方便的。如果还要修改其它的openwrt构建设置,可在make menuconfig
中选上此模块,然后重新编译openwrt。
2.1 离线安装模块包
在线安装最便捷,会自动安装依赖包,但需要网络条件。离线安装需要先下载好所需要的包,之后手动安装。
可使用LuCI网页界面安装,操作简单。简单直观,本文不再介绍。
下面介绍命令行安装方法,可在没有配置LuCI功能,或LuCI页面出错打不开时使用。
下载包:kernel、kmod-spi-bitbang、kmod-spi-dev、kmod-spi-gpio、kmod-spi-gpio-custom。其中只kmod-spi-gpio-custom是需要的spi-gpio-custom包,其它均为依赖包。
包要与操作系统及硬件主控对上。比如包名:
kmod-spi-gpio-custom_3.18.29-1-8876e460a901ba0991338a5b1846e893_ramips_24kec.ipk
其中,各部分的含义为:
- kmod-: 内核模块(Kernel Module)。
- spi-gpio-custom: 内核模块的具体名称。
- 3.18.29: 这是该内核模块所依赖的 Linux 内核版本。
- -1: 这是该软件包版本的修订号,通常用于追踪小的更新或修补。
- 8876e460a901ba0991338a5b1846e893: 这是一个校验和或唯一标识符,用于确保软件包的完整性和唯一性。
- ramips: 这表示该模块是为基于 Ralink/MediaTek MIPS 架构(ramips)的设备编译的。
- 24kec: 这是该 MIPS 架构下的一个特定型号或子架构。
- .ipk: 这是软件包的文件扩展名,表明它是一个用于 OpenWRT 的安装包。
模块包的安装命令opkg install
。如安装kmod-spi-gpio-custom包:
opkg install kmod-spi-gpio-custom*.ipk
在命令中,可用*
号用替代后续字符。
按照这个顺序依次安装:kernel、kmod-spi-bitbang、kmod-spi-dev、kmod-spi-gpio、kmod-spi-gpio-custom。
检验是否安装成功:
opkg list-installed | grep spi-gpio
看到kmod-spi-gpio-custom
,说明已安装好。
安装时,如还遇到缺少依赖包问题,需根据提示,依次安装。
2.2 编译安装
在系统源代码根目录,输入配置指令:
make menuconfig
在kernel model -> spi support,选中”kmod-spi-gpio-custom”,系统会自动选中三个依赖包:“kmod-spi-bitbang”、“kmod-spi-dev”、“kmod-spi-gpio”。
保存退出后,重新编译openwrt:
make j=2 //双线程编译
3 使用spi-gpio-custom模块配置SPI总线
spi-gpio-custom 的便利就在于可动态配置SPI总线,不需“修改dts文件、编译系统”的繁琐操作。也就是说,通过spi-gpio-custom使用spi时,dts文件中可以没有任何spi功能的定义。
常规的一个屏幕接口引脚定义
接口 | 功能 |
---|---|
MISO | SPI输出 |
MOSI | SPI输入 |
CLK | SPI时钟输入 |
DC | 数据/命令 切换控制,低电平表示输入命令,高电平表示输入数据 |
RES | 复位屏幕 |
BLK | 背光控制 |
VCC | 电源 |
GND | 接地 |
配置举例
配置一个ID为1的总线,使用GPIO3作为CLK,GPIO4作为MOSI,GPIO5作为MISO,在SPI模式0下工作、最大频率为20KHz、GPIO2作为CS的设备。
命令参数 功能描述
<id> ID to used as device_id for the corresponding bus (required)
<sck> GPIO pin ID to be used for bus SCK (required)
<mosi> GPIO pin ID to be used for bus MOSI (required*)
<miso> GPIO pin ID to be used for bus MISO (required*)
<modeX> Mode configuration for slave X in the bus (required) * (see /include/linux/spi/spi.h)
<maxfreqX> Maximum clock frequency in Hz for slave X in the bus (required)
<csX> GPIO pin ID to be used for slave X CS (required**)
运行命令:
insmod spi-gpio-custom bus0=1,3,4,5,0,20000,2
请注意GPIOx中的x,不是引脚编号(pin),而是引脚名称。
如需修改spi总线的配置,需先卸载后再加载:
rmmod spi-gpio-custom
insmod spi-gpio-custom <new parameters>
更复杂的配置,参考 原始文档: SPI over GPIO in OpenWrt
=========
MT7628dan 增加SPI接口
来源 https://blog.csdn.net/likang517/article/details/80864918
SPI是可以全双工通信的一种串行总线,两个设备之间双向通信的话一般使用3根线:SCLK,MISO,MOSI,多个设备之间双向通信的话,每个设备还需要再加上一根地址线CSn。相比之下I2C只能半双工,而且一般需要上拉电阻,但无论几个设备,都只需要2根线。更多基础知识请谷歌百度。
MT7628DAN芯片只有一个主控制器,但是有两个片选信号,可以接2个设备,其中一个已经被SPI FLASH占用,所以需要启用另外一个设备。
1、修改内核配置文件
make menuconfig
配置完成后退出保存。
1、修改文件mt7628an.dtsi
spi0: spi@b00 {
compatible = "ralink,mt7621-spi";
reg = <0xb00 0x100>;
resets = <&rstctrl 18>;
reset-names = "spi";
#address-cells = <1>;
#size-cells = <0>;
pinctrl-names = "default";
pinctrl-0 = <&spi_pins>,<&spi_cs1_pins>;
status = "disabled";
};
spi@b00代表一个spi控制器,是一个platform device,compatible = "ralink,mt7621-spi";和 platform driver 中的of_match_table 对应(如果要支持片选1,还得修改num_cs=2,前提是mt7628的spi控制器本来就支持两个片选).相同就会进入到probe函数中,再调用spi_register_master()注册一个spi主控制器.<&spi_cs1_pins>是新增片选引脚,文件mt7628an.dtsi中有定义:
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";
};
};
3、修改MT7628.dts 文件
/dts-v1/;
#include "mt7628an.dtsi"
/ {
compatible = "mediatek,mt7628an-eval-board", "mediatek,mt7628an-soc";
model = "Mediatek MT7628AN evaluation board";
memory@0 {
device_type = "memory";
reg = <0x0 0x2000000>;
};
};
&pinctrl {
state_default: pinctrl0 {
gpio {
ralink,group = "i2c";
ralink,function = "gpio";
};
};
};
&wmac {
status = "okay";
};
&spi0 {
status = "okay";
m25p80@0 {
#address-cells = <1>;
#size-cells = <1>;
compatible = "jedec,spi-nor";
reg = <0>;
spi-max-frequency = <10000000>;
m25p,chunked-io = <32>;
partition@0 {
label = "u-boot";
reg = <0x0 0x30000>;
read-only;
};
partition@30000 {
label = "u-boot-env";
reg = <0x30000 0x10000>;
read-only;
};
factory: partition@40000 {
label = "factory";
reg = <0x40000 0x10000>;
read-only;
};
partition@50000 {
label = "firmware";
reg = <0x50000 0x7b0000>;
};
};
spidev@1 {
compatible = "rohm,dh2228fv";
reg = <1 0>;
spi-max-frequency = <1000000>;
};
};
&wmac {
status = "okay";
};
spi_register_master注册spi主控制器时就会扫描这些设备,并注册这些设备。 status = “okay”表示选中,否则不能编译进内核. m25p80@0表示在spi片选0下挂了一个m25p80的设备,reg=<0,0>表示片选0,compatible = "jedec,spi-nor"; 与驱动文件匹配.如果要在spi控制器的片选1上挂一个设备,就要修改dts文件,修改如下:
spidev@1 {
compatible = "rohm,dh2228fv";
reg = <1 0>;
spi-max-frequency = <1000000>;
};
compatible = "rohm,dh2228fv";与 spidev.c文件中compatible 一致。
4、保存修改文件,执行make 生产升级固件
lede-snapshot-r7346-7b74b40-ramips-mt76x8-mt7628-squashfs-sysupgrade.bin
5、烧写固件查看设备文件:
6、好不好用还没有测试。
7、编译spi-test进行spi测试
8、执行
root@OpenWrt:/# spidev_test -D /dev/spidev0.1
出现如下一连串错误
spi mode: 0x0[ 196.130000] ------------[ cut here ]------------
bits per word:[ 196.130000] WARNING: CPU: 0 PID: 161 at drivers/spi/spi-mt7621.c:137 mt7621_spi_transfer_one_message+0x158/0x360()
8
max speed: 5[ 196.140000] Modules linked in:00000 Hz (500 KH qcserialz)
pppoe ppp_async option iptable_nat usb_wwan sierra pppox ppp_generic nf_nat_ipv4 nf_conntrack_ipv6 nf_conntrack_ipv4 ipt_REJECT ipt_MASQUERADE xt_time xt_tcpudp xt_state xt_nat xt_multiport xt_mark xt_mac xt_limit xt_id xt_conntrack xt_comment xt_TCPMSS xt_REDIRECT xt_LOG xt_CT usbserial spidev slhc nf_reject_ipv4 nf_nat_masquerade_ipv4 nf_nat_ftp nf_nat nf_log_ipv4 nf_defrag_ipv6 nf_defrag_ipv4 nf_conntrack_rtcache nf_conntrack_ftp nf_conntrack iptable_raw iptable_mangle iptable_filter ip_tables crc_ccitt i2c_gpio i2c_algo_bit i2c_dev i2c_core mt76x8 ralink_eeprom_api ledtrig_usbdev ip6t_REJECT nf_reject_ipv6 nf_log_ipv6 nf_log_common ip6table_raw ip6table_mangle ip6table_filter ip6_tables x_tables ipv6 mmc_block mmc_core leds_gpio ohci_platform ohci_hcd ehci_platform ehci_hcd gpio_button_hotplug usbcore nls_base usb_common
[ 196.220000] CPU: 0 PID: 161 Comm: spi32766 Tainted: G W 3.18.20 #8
[ 196.230000] Stack : 00000000 00000000 00000000 00000000 803441f2 00000042 00000000 801ae398
00000001 8f8c7b88 802a53d0 802fc9c3 000000a1 8034341c 8f900bf8 8f8c7b88
00010000 80309578 00000000 80047400 00000003 80024170 00000089 8f8c7b88
802a88d4 8f979d74 00000000 00000000 00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
...
[ 196.270000] Call Trace:
[ 196.270000] [<800140b4>] show_stack+0x48/0x70
[ 196.270000] [<800242ec>] warn_slowpath_common+0x84/0xb4
[ 196.280000] [<800243a4>] warn_slowpath_null+0x18/0x24
[ 196.290000] [<801ae398>] mt7621_spi_transfer_one_message+0x158/0x360
[ 196.290000] [<801ad4e8>] spi_pump_messages+0x3cc/0x438
[ 196.300000] [<80039b9c>] kthread_worker_fn+0xa8/0xf4
[ 196.300000] [<80039cc0>] kthread+0xd8/0xe4
[ 196.310000] [<80004878>] ret_from_kernel_thread+0x14/0x1c
[ 196.310000]
[ 196.310000] ---[ end trace 828b306131dd7246 ]---
can't send spi message: Input/output error
Aborted
查了好几天问题,没明白找到了一个帖子
http://dev.archive.openwrt.org/ticket/20521?action=new&attachfilebutton=Attach+file#no1
原因是
The spidev_test is transmitting a 38 bytes array, that is too large. The spi-mt7621.c will reject when Tx length > 16 (full duplex).
然后修改mt7621.c文件,把全双工注释掉可正常运行spi-test。
============
QCA9531修改寄存器值控制GPIO
来源 https://blog.csdn.net/cocos_yang/article/details/109249418
由高通9531芯片规格书可知,芯片对应的GPIO有18个GPIO0-17,下图是规格书定义。下面以SKYLAB的SKW99模块为例进行说明。
SKYLAB的SKW99模块使用源码为QSDK,GPIO0-3默认为JTAG功能,GPIO9和10为uart串口,剩下的GPIO11-16为默认为灯的功能,GPIO17为WPS按键功能。
GPIO11-17对应功能源码地址为:
qsdk/target/linux/ar71xx/files/arch/mips/ath79/mach-ap147.c
下面以在固件中控制GPIO0进行讲述说明,固件中需要有io工具:
1、将GPIO1转为GPIO功能:
下面是芯片规格书中关于GPIO0-3功能的定义:对应寄存器的地址为0x1804006C
读取寄存器0x1804006C寄存器的值:
root@OpenWrt:~# io -4 0x1804006C
1804006c: 00000020
root@OpenWrt:~#
高通规格书,没有详细介绍bit1值对应的功能,根据实践:
默认0,对应jtag(默认),1对应的是GPIO功能。
将bit1设置为1,则对应寄存器的值应设置为0x00000022
root@OpenWrt:/# io -4 0x1804006c 0x00000022 //写寄存器值
root@OpenWrt:/#
root@OpenWrt:/# io -4 0x1804006c //读寄存器值
1804006c: 00000022
root@OpenWrt:/#
2、对GPIO1进行操作
步骤如下:
(1)先注册GPIO1
root@OpenWrt:/# echo 1 > /sys/class/gpio/export
root@OpenWrt:/#
root@OpenWrt:/# echo out > /sys/class/gpio/gpio1/direction
root@OpenWrt:/#
(2)查看系统GPIO的状态
root@OpenWrt:/# cat /sys/kernel/debug/gpio
GPIOs 0-17, ath79:
gpio-0 (sysfs ) out lo
gpio-1 (sysfs ) out lo
gpio-13 (sysfs ) out hi
gpio-17 (WPS button ) in hi
root@OpenWrt:/#
(3)对GPIO1进行拉高操作
(4)对GPIO1进行拉低操作
同理Link1灯GPIO16的操作控制如下:寄存器为0x1804003C,bit0-bit7对应GPIO16.
============== End
标签:kmod,SPI,00000000,custom,spi,gpio From: https://www.cnblogs.com/lsgxeva/p/18504347