在f1c100s芯片上移植spi网卡enc28j60的linux驱动

这篇具有很好参考价值的文章主要介绍了在f1c100s芯片上移植spi网卡enc28j60的linux驱动。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

前言

我个人与全志的芯片颇有故事。在我还是一个不懂事的高中生时,我看到荔枝派的官方文档,顿时被这小小的板子给吸引住。点开文档的初见:

荔枝派Nano(下面简称Nano)是一款精致迷你的 Arm9 核心板/开发板,可用于初学者学习linux或者商用于产品开发。 Nano 在与SD卡相当的尺寸上(25.4 * 33mm)提供了丰富的外设 (LCD,UART,SPI,I2C,PWM,SDIO,KEYADC...)和较为强劲的性能(24M~408MHz, 32MB DDR)。
Nano 延续并发展了Zero精巧的PCB设计,使得开发和使用非常方便:

2.54mm排针直插面包板
直插40P RGB LCD
使用OTG口进行供电和数据传输(虚拟串口,更新固件等)
可配合使用使用堆叠式的WiFi 模块联网
?可直接贴片

当时高一的我连什么是单片机和微处理器都分不清楚,只觉得好神奇,居然有这样一种单片机,性能居然这么强悍,芯片封装那么小,还能跑linux?于是速速下单买了一块荔枝派回来。拿到手也不咋会用,照着教程不是报错就是缺库,再加上学业繁重,就放在那吃灰了。

后来高二暑假,再次捡起这块板子,把uboot编译了,又把磕磕碰碰地把linux的设备树照抄过来,磕磕碰碰地开了两个窗口照抄内核配置。当时就是喜欢配内核,配来配去,虽然这个过程非常操蛋,但是当终于解决了好多文档里根本不提的问题(比如说regulator必须要在内核配置中打开等)后,又觉得人生十分圆满,我终于会搞嵌入式linux了。21年的高二暑假把内核和rootfs配好后,手上刚好又有个为了给单片机提供以太网用的enc28j60模块。刚好点开linux的menuconfig,也发现内核支持这个模块,从此就和enc28j60结下了梁子。

我用的内核版本是5.4

第一次移植过程

在我脑海中,我依稀记得当初有多稚嫩。我在whycan上翻来翻去,总算知道了给linux内核加驱动要改设备树。然后我去翻了半天linux的documentation,却还是没搞懂设备树到底要怎么写。这不纯纯坑人+浪费时间吗?当时高二期末考试前没事干,就用电脑一直翻torvalds/linux仓库的源码,把enc28j60的源码看了,看不懂,又去看设备树的源代码,那个更加是天书,不知道在说个啥。后来放假了,就动手开始移植,我首先打开了linux/Documentation/devicetree/bindings/net/microchip,enc28j60.txt,这个是驱动开发者为我们留下的文档,让我们看看他说了个啥

* Microchip ENC28J60

This is a standalone 10 MBit ethernet controller with SPI interface.

For each device connected to a SPI bus, define a child node within
the SPI master node.

Required properties:
- compatible: Should be "microchip,enc28j60"
- reg: Specify the SPI chip select the ENC28J60 is wired to
- interrupts: Specify the interrupt index within the interrupt controller (referred
              to above in interrupt-parent) and interrupt type. The ENC28J60 natively
              generates falling edge interrupts, however, additional board logic
              might invert the signal.
- pinctrl-names: List of assigned state names, see pinctrl binding documentation.
- pinctrl-0: List of phandles to configure the GPIO pin used as interrupt line,
             see also generic and your platform specific pinctrl binding
             documentation.

Optional properties:
- spi-max-frequency: Maximum frequency of the SPI bus when accessing the ENC28J60.
  According to the ENC28J80 datasheet, the chip allows a maximum of 20 MHz, however,
  board designs may need to limit this value.

The MAC address will be determined using the optional properties
defined in ethernet.txt.

Example (for NXP i.MX28 with pin control stuff for GPIO irq):

        ssp2: ssp@80014000 {
                compatible = "fsl,imx28-spi";
                pinctrl-names = "default";
                pinctrl-0 = <&spi2_pins_b &spi2_sck_cfg>;

                enc28j60: ethernet@0 {
                        compatible = "microchip,enc28j60";
                        pinctrl-names = "default";
                        pinctrl-0 = <&enc28j60_pins>;
                        reg = <0>;
                        interrupt-parent = <&gpio3>;
                        interrupts = <3 IRQ_TYPE_EDGE_FALLING>;
                        spi-max-frequency = <12000000>;
                };
        };

        pinctrl@80018000 {
                enc28j60_pins: enc28j60_pins@0 {
                        reg = <0>;
                        fsl,pinmux-ids = <
                                MX28_PAD_AUART0_RTS__GPIO_3_3    /* Interrupt */
                        >;
                        fsl,drive-strength = <MXS_DRIVE_4mA>;
                        fsl,voltage = <MXS_VOLTAGE_HIGH>;
                        fsl,pull-up = <MXS_PULL_DISABLE>;
                };
        };

我们发现配置好enc28j60模块,首先我们需要一个能用的spi设备节点。然后把我们的以太网设备挂在这个节点下,并且为它指定外部中断引脚。
于是我便照猫画虎,靠着代码能力把这一部分设备树的代码移植了过去。我知道这个设备树代码的意图是啥,但有的谜语是真的想不通:

  • 什么是ssp?我猜应该是spi吧
  • 为什么&ssp2enc28j60节点下都要塞一个pinctrl-names and pinctrl-0,这些是干嘛的
  • 为什么enc28j60pinctrlssp2的不一样?
  • interrupt-parentinterrupts是什么鬼?在全志平台上这俩参数应该咋写?
  • enc28j60_pins的意图是来一个GPIO的外部中断的引脚配置,这个在全志平台又得咋写?

当时怎么也无法思索出结果,随便瞎折腾了好几个星期,最后还是放弃了,又因为学业繁重,备战高考,一年多也没碰过这个荔枝派。高三后再试了一次,还是以失败告终。高一暑假买了荔枝派回来吃灰,高二暑假开始尝试却啥也不懂,高三暑假再次放弃,这一切成了我的一个心结,直到来到华子的一周年纪念日,我才琢磨出了这一切。

第二次移植过程

这几天突然发现可以在linux代码仓库里边用它的搜索功能全局搜索想要的代码,于是我就开始了递归学习。打开suniv-f1c100s.dtsi,对这里边的compatible等字符串一顿乱搜,终于发现了sunxi做bsp驱动移植的秘密,但是这些太复杂了,说也说不完,让我们直接开始移植。前置条件是首先应该先准备好一个已经调通的uboot、内核与根文件系统。

第零步:接线

  • VCC ---> 3V3
  • CS ---> PE7 (SPI1_CS)
  • SI ---> PE8 (SPI1_MOSI)
  • SCK ---> PE9 (SPI1_CLK)
  • SO ---> PE10 (SPI1_MISO)
  • INT ---> PE11
  • GND ---> GND

需要注意的是,全志f1c系列芯片只有GPIOD GPIOE GPIOF有外部中断,所以在选取引脚时要特别注意,而且要关注这个引脚是否被开发板引出了。

第一步:配置Menuconfig

终端输入make menuconfig,使能以下config:

  • Device Drivers ---> Network device support ---> Ethernet driver support ---> Microchip devices ---> ENC28J60 support
  • Device Drivers ---> SPI support

ENC28J60可以编译为模块,也可以直接编译进内核。保存.config

第二步:修改设备树

接着让我们修改设备树。根据驱动开发者留给我们的文档,我们初步的设备树需要的改动如下:

suniv-f1c100s.dtsi:在pinctrl下加入spi和enc28j60的中断引脚定义

pio: pinctrl@1c20800 {
        compatible = "allwinner,suniv-f1c100s-pinctrl";
        reg = <0x01c20800 0x400>;
        interrupts = <38>, <39>, <40>;
        clocks = <&ccu CLK_BUS_PIO>, <&osc24M>, <&osc32k>;
        clock-names = "apb", "hosc", "losc";
        gpio-controller;
        interrupt-controller;
        #interrupt-cells = <3>;
        #gpio-cells = <3>;

        uart0_pe_pins: uart0-pe-pins {
                pins = "PE0", "PE1";
                function = "uart0";
        };

        uart1_pa_pins: uart1-pa-pins {
                pins = "PA2", "PA3";
                function = "uart1";
        };
        
        mmc0_pins: mmc0-pins {
                pins = "PF0", "PF1", "PF2", "PF3", "PF4", "PF5";
                function = "mmc0";
        };

        spi0_pins: spi0-pins{
                        pins = "PC0", "PC1", "PC2", "PC3";
                        function = "spi0";
        };
        
        spi1_pins: spi1-pins{
                pins="PE9","PE7","PE10","PE8";
                function = "spi1";
        };

        enc28j60_pins: enc28j60_pins{
                pins="PE11";
                function = "irq";
        };

};

改变引脚基本就是对着手册和文档照猫画虎的事情,这个引脚的function应该如何选取呢?让我们打开内核代码中的pinctrl-suniv-f1c100s.c

SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 7),
        SUNXI_FUNCTION(0x0, "gpio_in"),
        SUNXI_FUNCTION(0x1, "gpio_out"),
        SUNXI_FUNCTION(0x2, "csi"),  /* D4 */
        SUNXI_FUNCTION(0x3, "uart2"),  /* TX */
        SUNXI_FUNCTION(0x4, "spi1"),  /* CS */
        SUNXI_FUNCTION_IRQ_BANK(0x6, 1, 7)),
SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 8),
        SUNXI_FUNCTION(0x0, "gpio_in"),
        SUNXI_FUNCTION(0x1, "gpio_out"),
        SUNXI_FUNCTION(0x2, "csi"),  /* D5 */
        SUNXI_FUNCTION(0x3, "uart2"),  /* RX */
        SUNXI_FUNCTION(0x4, "spi1"),  /* MOSI */
        SUNXI_FUNCTION_IRQ_BANK(0x6, 1, 8)),
SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 9),
        SUNXI_FUNCTION(0x0, "gpio_in"),
        SUNXI_FUNCTION(0x1, "gpio_out"),
        SUNXI_FUNCTION(0x2, "csi"),  /* D6 */
        SUNXI_FUNCTION(0x3, "uart2"),  /* RTS */
        SUNXI_FUNCTION(0x4, "spi1"),  /* CLK */
        SUNXI_FUNCTION_IRQ_BANK(0x6, 1, 9)),
SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 10),
        SUNXI_FUNCTION(0x0, "gpio_in"),
        SUNXI_FUNCTION(0x1, "gpio_out"),
        SUNXI_FUNCTION(0x2, "csi"),  /* D7 */
        SUNXI_FUNCTION(0x3, "uart2"),  /* CTS */
        SUNXI_FUNCTION(0x4, "spi1"),  /* MISO */
        SUNXI_FUNCTION_IRQ_BANK(0x6, 1, 10)),
SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 11),
        SUNXI_FUNCTION(0x0, "gpio_in"),
        SUNXI_FUNCTION(0x1, "gpio_out"),
        SUNXI_FUNCTION(0x2, "clk0"),  /* OUT */
        SUNXI_FUNCTION(0x3, "i2c0"),  /* SCK */
        SUNXI_FUNCTION(0x4, "ir"),  /* RX */
        SUNXI_FUNCTION_IRQ_BANK(0x6, 1, 11)),
SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 12),
        SUNXI_FUNCTION(0x0, "gpio_in"),
        SUNXI_FUNCTION(0x1, "gpio_out"),
        SUNXI_FUNCTION(0x2, "i2s"),  /* MCLK */
        SUNXI_FUNCTION(0x3, "i2c0"),  /* SDA */
        SUNXI_FUNCTION(0x4, "pwm0"),  /* PWM0 */
        SUNXI_FUNCTION_IRQ_BANK(0x6, 1, 12)),

所以,我们现在知道了function这个字符串的值域。那么对于外部中断引脚,应该怎么填function呢?像spi的功能,上面的代码告诉我们,直接填spi1,那么SUNXI_FUNCTION_IRQ_BANK又是个啥?继续看它的头文件pinctrl-sunxi.h

#define SUNXI_FUNCTION_IRQ(_val, _irq)    \
{       \
        .name = "irq",     \
        .muxval = _val,     \
        .irqnum = _irq,     \
}

#define SUNXI_FUNCTION_IRQ_BANK(_val, _bank, _irq)  \
{       \
        .name = "irq",     \
        .muxval = _val,     \
        .irqbank = _bank,    \
        .irqnum = _irq,     \
}

所以我猜对于中断引脚,我们应该把function设置为irq,这样他就会自动帮我们初始化这个引脚的复用功能(全志可能没这个说法)。

接下来让我们修改suniv-f1c100s-licheepi-nano.dts

&spi1{
        status = "okay";
        pinctrl-names = "default";
        pinctrl-0 = <&spi1_pins>;
        enc28j60: ethernet@0 {
                compatible = "microchip,enc28j60";
                pinctrl-names = "default";
                pinctrl-0 = <&enc28j60_pins>;
                reg = <0>;
                interrupt-parent = <&pio>;
                interrupts = <4 11 IRQ_TYPE_EDGE_FALLING>;
                spi-max-frequency = <12000000>;
        };
};

这里基本就是对着全志设备树,照着它文档抄了。现在我们也可以解答一下我高中时代的疑问。这个interrupt-parent是啥呢?interrupt-parent属性用于指定中断路由到的控制器,并包含引用中断控制器节点的单个 phandle。 该属性是继承的,因此可以在中断客户端节点或其任何父节点中指定。 “中断”属性中列出的中断始终引用节点的中断父级。翻译成人话就是它用的中断要对应在哪个中断控制器,至少在本芯片内是一种些许无用的抽象,因为f1c100s就一个简单的中断控制器INTC,但是对于更复杂的片上中断控制器则是特别好的设计。并且这样做也方便了我们配置外部引脚的中断。

dtsi中的#interrupt-cells = <3>告诉我们,interrupts这个属性应该有3个元素。通过翻其它全志的设备树,我们也知道了应该要如何配置interrupts这个属性。那就是先放引脚Port的编号,那就是A放0,B放1,C放2,D放3,E放4。。。第二个参数是引脚编号,我们用的PE11,直接填。第三个参数,直接抄模块的文档。

现在已经大功告成,让我们拷贝好设备树和内核镜像,准备启动!

第三步:启动内核

启动内核后,我们dmesg,发现并没有任何关于enc28j60的影子,甚至连关于spi的影子也没有,这是怎么回事呢?再折腾了好几天后,我发现这是因为spi根本就没有被加载。我们芯片设备树对spi的配置中是这样配置compatible属性的:"allwinner,suniv-spi", "allwinner,sun8i-h3-spi",事实上,linux内核中根本没有代码去适配allwinner,suniv-spi,所以内核会去找allwinner,sun8i-h3-spi。而在drivers/spi/spi-sun6i.c中:

static const struct of_device_id sun6i_spi_match[] = {
        { .compatible = "allwinner,sun6i-a31-spi", .data = &sun6i_a31_spi_cfg },
        { .compatible = "allwinner,sun8i-h3-spi",  .data = &sun8i_h3_spi_cfg },
        {
                .compatible = "allwinner,sun50i-r329-spi",
                .data = &sun50i_r329_spi_cfg

所以我们来到内核配置Device Drivers ---> SPI support,发现allwinner的spi就俩,一个Allwinner A31 SPI controller,一个Allwinner A31 SPI controller。查看Kconfig后发现,后者对应的symbol是SPI_SUN6I。故我们应该将后者设置成Y。而我之前是将前者设置成Y,后者设置成了N。

再次启动内核,一切都顺利加载

...

[    1.098960] enc28j60 spi0.0: Ethernet driver 1.02 probed
[    1.104485] enc28j60 spi0.0: Ethernet driver 1.02 loaded

....

[    4.343318] enc28j60 spi0.0 eth0: link down
Starting ntpd: [    4.354284] enc28j60 spi0.0 eth0: normal mode
[    4.359272] enc28j60 spi0.0 eth0: multicast mode
OK
[    5.292753] enc28j60 spi0.0 eth0: link up - Half duplex

...

移植之后

我的rootfs没有dhcp的软件,没法自动拿ip地址。所以我们需要配置一下buildroot。
进入目录,make menuconfig,进入
Target packages ---> Networking applications,勾上以下内容:

  • dhcp
    • dhcp relay
    • dhcp client
  • dhcpd
  • dhcpdump
  • dnsmasq
    • tftp support
    • dhcp support
  • ethtool
    • enable pretty printing
  • hostapd
  • httping
  • iptables
  • iw
  • lrzsz
  • ntp
    • ntpd
    • ntptime
  • openssh
    • client
    • server
    • key utilities
  • tcpdump
  • wget

再次重新上电,进入系统,输入ifconfig,非常漂亮地拿到了ip地址,不过由于校园网需要认证,目前没法访问内网和外网。

# ifconfig
eth0      Link encap:Ethernet  HWaddr 96:54:CC:C7:65:B4
          inet addr:59.66.*.*  Bcast:59.66.*.*  Mask:255.255.255.0
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:953 errors:0 dropped:0 overruns:0 frame:0
          TX packets:44 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000
          RX bytes:70235 (68.5 KiB)  TX bytes:3760 (3.6 KiB)
          Interrupt:67

lo        Link encap:Local Loopback
          inet addr:127.0.0.1  Mask:255.0.0.0
          UP LOOPBACK RUNNING  MTU:65536  Metric:1
          RX packets:128 errors:0 dropped:0 overruns:0 frame:0
          TX packets:128 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000
          RX bytes:9472 (9.2 KiB)  TX bytes:9472 (9.2 KiB)

困扰了两年的心结,从高二困扰到大一,终于解决了!文章来源地址https://www.toymoban.com/news/detail-677007.html

到了这里,关于在f1c100s芯片上移植spi网卡enc28j60的linux驱动的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • modbus采集和 mqtt上报相结合,通过荔枝派(F1c100s芯片模块)实现数据采集连接阿里云物联网平台进行数据上报和下发功能。

    通过荔枝派(F1c100s芯片模块)搭载SDIO-wifi模块,写入了主函数程序。根据读取modbus模拟器的数据,反馈到阿里云物联网平台当中。图中左侧的阿里云物联网平台所显示的温度为66摄氏度,与modbus模拟器的数据是一样的,图片右侧是荔枝派(F1c100s芯片模块)的编程软件X-shell的

    2024年02月15日
    浏览(44)
  • 全志F1C100s主线linux入坑记录 (6)音视频播放(视频播放软解)

    百度网站 (1)下载安装声卡补丁 参考挖坑网大神提供的声音驱动以及声音卡驱动补丁文件下载文件下载 全志F1C100s声卡补丁 解压文件打上补丁 (2)配置声卡 修改设备树文件添加声卡节点 内核配置 (3)linux内核编译烧录 可以看到声卡已经挂载了 (4)使用声卡 安装alsa-u

    2024年02月07日
    浏览(36)
  • 7、Lctech Pi(F1C200S)开启RNDIS,通过USB与电脑联网(CherryPi,Mangopi,F1C100S)

    本次主要参考: 荔枝nano开启RNDIS驱动,无需补丁。 https://github.com/peng-zhihui/Planck-Pi#head23 https://github.com/mangopi-sbc/buildroot-mangopi-r https://www.cnblogs.com/listenscience/p/13758272.html (如果方便请给这几位大佬一个关注) 注意代码块之间的空行 本次是摸索出来的,如果用到项目需慎重,有

    2024年02月12日
    浏览(30)
  • linux(全志F1C100S/F1C200S)系列02:移植LCD st7789驱动,LVGL8.3移植

    st7789V中指定了rst与dc引脚,pio 4 3 对应PE3,pio 4 5对应PE5; 详细配置方式见链接:全志 :gpio使用 需要根据自身硬件配置。 Tips:更改 spi-max-frequency = 32000000 - spi-max-frequency = 100000000; 和 fps = 30; 改为 fps = 60; 感谢楼下老哥提示。 rotate = 90;根据屏幕方向更改。 只需要更改下面的三个地

    2024年01月18日
    浏览(53)
  • 【f1c200s/f1c100s】mangopi自制linux开发板驱动适配进度(PCB、代码开源)

    目前自制的mangopi设备驱动适配已完成部分包含: 基于扫描的gpio-keys子系统适配 LED子系统适配 RGB接口LCD显示屏适配 ft5406触摸屏适配 博通RTL8188EUS无线网卡适配 PWM驱动适配 显示屏背光适配 以下这几项在下载到荔枝派源码时已经适配好了: SPI FLASH驱动 USB驱动 串口驱动 mangopi内

    2024年02月03日
    浏览(79)
  • 全志F1C200S嵌入式驱动开发(spi-nand驱动)

    【 声明:版权所有,欢迎转载,请勿用于商业用途。 联系信箱:feixiaoxing @163.com】         和v3s一样,f1c200s也支持tf卡、spi-nor、spi-nand启动。前面也说过,tf卡由于机械结构的原因,更适合拿来学习,spi-nor和spi-nand比较适合用来进行工业部署和消费娱乐领域。只是spi-nor容量

    2024年02月16日
    浏览(46)
  • 全志F1C200S嵌入式驱动开发(spi-nor image制作)

    【 声明:版权所有,欢迎转载,请勿用于商业用途。 联系信箱:feixiaoxing @163.com】         一般soc系统里面添加spi-nor flash芯片,特别是对linux soc来说,都是把它当成文件系统来使用的。spi-nor flash和spi-nand flash相比,虽然空间小了点,但是胜在稳定,这是很多工业场景所必须

    2024年02月16日
    浏览(35)
  • (三)内核移植--从零开始自制linux掌上电脑(F1C200S)<嵌入式项目>

    目录 一、bootloader、kernel、rootfs联系 二、内核移植 1. 内核源码获取 2. 内核配置与编译 🍍 基础配置与编译 🍍 TF卡分区 🍍 内核烧录 三、参考内容 kernel可以理解为一个 庞大的裸机程序 ,和uboot以及其他比如点灯类似的裸机程序没有本质区别,只是kernel分为 用户态和内核态

    2024年02月15日
    浏览(66)
  • F1C200S/F1C100S修改U-BOOT调试串口为UART1(PD3,PD4)

    此处用的uboot是荔枝派nano的 可以从荔枝派的仓库拉取 修改好的在这 查看串口挂载总线 查看数据手册 根据总线图可以看出串口是挂载在APB总线上面的 找到总线时钟设置部分 使能UART1控制器时钟 原本以为要改这,但是后来发现不需要修改。。。 设置GPIO引脚复用功能 直接pd

    2024年02月14日
    浏览(39)
  • f1c200s---编译uboot

    本章所解决问题后的Uboot仓库、docker镜像可在文章末尾找到,如果不想一步步配置编译环境可到文章末尾下载docker镜像直接运行 下载交叉编译链: 解压交叉编译链: 配置环境变量: 打开后在文件最后一行添加以下变量: 生效环境变量: 查询版本确保安装无误: 由于官方

    2024年02月07日
    浏览(33)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包