与 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