与 FPGA 的 SPI 接口 运行 LINUX
SPI interface with FPGA running LINUX
我有一个 DE1-SoC FPGA 运行 Ubuntu 16.04 通过 microSD 卡。我对设备树有些陌生,但已经设法弄清楚如何通过使用 dtc 将 .dtb 文件反编译为 .dts 文件来启用电路板上的各种外围设备。我这样做了,并在 nano 中编辑了 .dts 文件,将 SPI 端口从 "disabled" 更改为 "okay"。然后我从修改后的 .dts 文件重新编译 .dtb 文件(我还删除了 .dts 文件并重新编译了第二个 .dts 文件以查看更改是否生效,它们确实生效了)。
此时,我重新启动系统,然后转到 cd/dev/ 但没有列出 spidev 或 spi* 或 spidev*。当我转到 cd/proc/device-tree 时,我列出了以下内容:
ubuntu@DE1_SoC:/proc/device-tree$ dir
3-3-v-regulator chosen leds name
#address-cells compatible __local_fixups__ #size-cells
aliases cpus memory soc
bridge@0xff200000 intc@fffed000 model __symbols__
当我导航到 /soc/ 文件夹时,我有以下内容,这与我的 .dts 文件一致:
ubuntu@DE1_SoC:/proc/device-tree/soc$ dir
#address-cells gpio@ff70a000 #size-cells
amba i2c@ffc04000 snoop-control-unit@fffec000
base-fpga-region i2c@ffc05000 spi@ff705000
can@ffc00000 i2c@ffc06000 spi@fff00000
can@ffc01000 i2c@ffc07000 spi@fff01000
clkmgr@ffd04000 interrupt-parent sram@ffff0000
compatible l2-cache@fffef000 sysmgr@ffd08000
device_type l2edac@xffd08140 timer0@ffc08000
dwmmc0@ff704000 l3regs@0xff800000 timer1@ffc09000
ethernet@ff700000 name timer2@ffd00000
ethernet@ff702000 nand@ff900000 timer3@ffd01000
fpga2sdram-bridge ocramedac@ffd08144 timer@fffec600
fpga-bridge@ff400000 ranges usb@ffb00000
fpga-bridge@ff500000 rstmgr@ffd05000 usb@ffb40000
fpga-bridge@ff600000 sdramedac usbphy@0
fpga-mgr@ff706000 sdr@ffc25000 watchdog@ffd02000
gpio@ff708000 serial0@ffc02000 watchdog@ffd03000
gpio@ff709000 serial1@ffc03000
所以,我不确定我做错了什么,我的串行外设接口不工作。最终目标:FPGA 上的 SPI 连接到板载 ADC (AD7928),我想使用 C 编写的程序通过 Linux 访问它。i2C 工作正常,但由于某种原因 SPI 不是回应。
我想我可能漏掉了一步,但在这一点上我有点迷路了,所以任何帮助都会很棒。
编辑:忘记为 SPI 添加 .dts 条目:
spi@fff00000 {
compatible = "snps,dw-apb-ssi";
#address-cells = <0x1>;
#size-cells = <0x0>;
reg = <0xfff00000 0x1000>;
interrupts = <0x0 0x9a 0x4>;
num-cs = <0x4>;
tx-dma-channel = <0x2c 0x10>;
rx-dma-channel = <0x2c 0x11>;
clocks = <0x11>;
status = "okay";
linux,phandle = <0x59>;
phandle = <0x59>;
};
spi@fff01000 {
compatible = "snps,dw-apb-ssi";
#address-cells = <0x1>;
#size-cells = <0x0>;
reg = <0xfff01000 0x1000>;
interrupts = <0x0 0x9b 0x4>;
num-cs = <0x4>;
tx-dma-channel = <0x2c 0x14>;
rx-dma-channel = <0x2c 0x15>;
clocks = <0x11>;
status = "okay";
linux,phandle = <0x5a>;
phandle = <0x5a>;
};
并且地址与开发板的datasheet SPIM 一致。
通过添加更多编辑 .dts 来获得一点回旋余地:
spi@fff00000 {
compatible = "snps,dw-apb-ssi";
#address-cells = <0x1>;
#size-cells = <0x0>;
reg = <0xfff00000 0x1000>;
interrupts = <0x0 0x9a 0x4>;
num-cs = <0x4>;
tx-dma-channel = <0x2c 0x10>;
rx-dma-channel = <0x2c 0x11>;
clocks = <0x11>;
status = "okay";
linux,phandle = <0x59>;
phandle = <0x59>;
spidev@0 {
compatible = "spidev";
reg = <0x0>;
spi-max-frequency = <0xb71b00>;
enable-dma = <0x0>;
}
现在 spidev32766.0 出现在我的 /dev/ 文件夹中。
spidev32766.0为添加设备树节点后得到的设备节点spidev@0
对于第一个 SPI 总线(控制器)上的 SPI 设备 spi@fff00000
芯片 select 0.
Frequency 属性 spi-max-frequency = <0xb71b00>
按照惯例应该使用十进制格式 12000000,而不是十六进制,并且在 spidev.c 的新版本中,驱动程序会抱怨 compatible = "spidev"
属性,因为这个 属性 应该描述真正的硬件而不是一些软件抽象。
这个32766总线(控制器)号是内核动态分配的,完全合法。
在较旧的内核中,在设备树文件之前,必须在板文件平台数据中定义总线编号,例如:.bus_num = 0,
如前所述,/dev
文件系统下没有 SPI 总线(控制器)设备节点 spiX
,只有客户端(芯片)设备节点 spidevX.Y
。
spidev.c
是一种为通用 SPI 客户端(芯片)设备注册的特殊驱动程序,其主要目标是通过创建字符将内核低级 SPI API 导出到用户空间/dev
接口下的设备节点。
但是如果您的目标是用于 ADC 的 SPI 驱动程序,也许最好为该芯片使用现有的 Linux SPI 驱动程序,例如对于 AD7791,或自己编写。
Linux 为工业 I/O 子系统 (iio) 设备提供支持,例如模数转换器。
Linux Kernel Configuration
Device Drivers --->
...
<*> Industrial I/O support --->
--- Industrial I/O support
...
Analog to digital converters --->
...
<*> Analog Devices ADXYZ* ADC driver
在这种情况下,Linux 会将您的 ADC 设备功能导出到 /sys
文件系统中的用户空间:
/sys/bus/iio/devices/iio:deviceX
设备属性可作为文件访问:
-r--r--r-- 1 root root 4096 Jan 1 04:18 name
drwxr-xr-x 2 root root 0 Jan 1 04:18 power
-rw-r--r-- 1 root root 4096 Jan 1 04:18 sampling_frequency
-r--r--r-- 1 root root 4096 Jan 1 04:18 sampling_frequency_available
我有一个 DE1-SoC FPGA 运行 Ubuntu 16.04 通过 microSD 卡。我对设备树有些陌生,但已经设法弄清楚如何通过使用 dtc 将 .dtb 文件反编译为 .dts 文件来启用电路板上的各种外围设备。我这样做了,并在 nano 中编辑了 .dts 文件,将 SPI 端口从 "disabled" 更改为 "okay"。然后我从修改后的 .dts 文件重新编译 .dtb 文件(我还删除了 .dts 文件并重新编译了第二个 .dts 文件以查看更改是否生效,它们确实生效了)。
此时,我重新启动系统,然后转到 cd/dev/ 但没有列出 spidev 或 spi* 或 spidev*。当我转到 cd/proc/device-tree 时,我列出了以下内容:
ubuntu@DE1_SoC:/proc/device-tree$ dir
3-3-v-regulator chosen leds name
#address-cells compatible __local_fixups__ #size-cells
aliases cpus memory soc
bridge@0xff200000 intc@fffed000 model __symbols__
当我导航到 /soc/ 文件夹时,我有以下内容,这与我的 .dts 文件一致:
ubuntu@DE1_SoC:/proc/device-tree/soc$ dir
#address-cells gpio@ff70a000 #size-cells
amba i2c@ffc04000 snoop-control-unit@fffec000
base-fpga-region i2c@ffc05000 spi@ff705000
can@ffc00000 i2c@ffc06000 spi@fff00000
can@ffc01000 i2c@ffc07000 spi@fff01000
clkmgr@ffd04000 interrupt-parent sram@ffff0000
compatible l2-cache@fffef000 sysmgr@ffd08000
device_type l2edac@xffd08140 timer0@ffc08000
dwmmc0@ff704000 l3regs@0xff800000 timer1@ffc09000
ethernet@ff700000 name timer2@ffd00000
ethernet@ff702000 nand@ff900000 timer3@ffd01000
fpga2sdram-bridge ocramedac@ffd08144 timer@fffec600
fpga-bridge@ff400000 ranges usb@ffb00000
fpga-bridge@ff500000 rstmgr@ffd05000 usb@ffb40000
fpga-bridge@ff600000 sdramedac usbphy@0
fpga-mgr@ff706000 sdr@ffc25000 watchdog@ffd02000
gpio@ff708000 serial0@ffc02000 watchdog@ffd03000
gpio@ff709000 serial1@ffc03000
所以,我不确定我做错了什么,我的串行外设接口不工作。最终目标:FPGA 上的 SPI 连接到板载 ADC (AD7928),我想使用 C 编写的程序通过 Linux 访问它。i2C 工作正常,但由于某种原因 SPI 不是回应。
我想我可能漏掉了一步,但在这一点上我有点迷路了,所以任何帮助都会很棒。
编辑:忘记为 SPI 添加 .dts 条目:
spi@fff00000 {
compatible = "snps,dw-apb-ssi";
#address-cells = <0x1>;
#size-cells = <0x0>;
reg = <0xfff00000 0x1000>;
interrupts = <0x0 0x9a 0x4>;
num-cs = <0x4>;
tx-dma-channel = <0x2c 0x10>;
rx-dma-channel = <0x2c 0x11>;
clocks = <0x11>;
status = "okay";
linux,phandle = <0x59>;
phandle = <0x59>;
};
spi@fff01000 {
compatible = "snps,dw-apb-ssi";
#address-cells = <0x1>;
#size-cells = <0x0>;
reg = <0xfff01000 0x1000>;
interrupts = <0x0 0x9b 0x4>;
num-cs = <0x4>;
tx-dma-channel = <0x2c 0x14>;
rx-dma-channel = <0x2c 0x15>;
clocks = <0x11>;
status = "okay";
linux,phandle = <0x5a>;
phandle = <0x5a>;
};
并且地址与开发板的datasheet SPIM 一致。
通过添加更多编辑 .dts 来获得一点回旋余地:
spi@fff00000 {
compatible = "snps,dw-apb-ssi";
#address-cells = <0x1>;
#size-cells = <0x0>;
reg = <0xfff00000 0x1000>;
interrupts = <0x0 0x9a 0x4>;
num-cs = <0x4>;
tx-dma-channel = <0x2c 0x10>;
rx-dma-channel = <0x2c 0x11>;
clocks = <0x11>;
status = "okay";
linux,phandle = <0x59>;
phandle = <0x59>;
spidev@0 {
compatible = "spidev";
reg = <0x0>;
spi-max-frequency = <0xb71b00>;
enable-dma = <0x0>;
}
现在 spidev32766.0 出现在我的 /dev/ 文件夹中。
spidev32766.0为添加设备树节点后得到的设备节点spidev@0
对于第一个 SPI 总线(控制器)上的 SPI 设备 spi@fff00000
芯片 select 0.
Frequency 属性 spi-max-frequency = <0xb71b00>
按照惯例应该使用十进制格式 12000000,而不是十六进制,并且在 spidev.c 的新版本中,驱动程序会抱怨 compatible = "spidev"
属性,因为这个 属性 应该描述真正的硬件而不是一些软件抽象。
这个32766总线(控制器)号是内核动态分配的,完全合法。
在较旧的内核中,在设备树文件之前,必须在板文件平台数据中定义总线编号,例如:.bus_num = 0,
如前所述,/dev
文件系统下没有 SPI 总线(控制器)设备节点 spiX
,只有客户端(芯片)设备节点 spidevX.Y
。
spidev.c
是一种为通用 SPI 客户端(芯片)设备注册的特殊驱动程序,其主要目标是通过创建字符将内核低级 SPI API 导出到用户空间/dev
接口下的设备节点。
但是如果您的目标是用于 ADC 的 SPI 驱动程序,也许最好为该芯片使用现有的 Linux SPI 驱动程序,例如对于 AD7791,或自己编写。 Linux 为工业 I/O 子系统 (iio) 设备提供支持,例如模数转换器。
Linux Kernel Configuration
Device Drivers --->
...
<*> Industrial I/O support --->
--- Industrial I/O support
...
Analog to digital converters --->
...
<*> Analog Devices ADXYZ* ADC driver
在这种情况下,Linux 会将您的 ADC 设备功能导出到 /sys
文件系统中的用户空间:
/sys/bus/iio/devices/iio:deviceX
设备属性可作为文件访问:
-r--r--r-- 1 root root 4096 Jan 1 04:18 name
drwxr-xr-x 2 root root 0 Jan 1 04:18 power
-rw-r--r-- 1 root root 4096 Jan 1 04:18 sampling_frequency
-r--r--r-- 1 root root 4096 Jan 1 04:18 sampling_frequency_available